Refactor useBooksManager and make it reusable

This commit is contained in:
chrox
2024-11-12 14:05:46 +01:00
parent ebe28dcd66
commit 3e99e68327
9 changed files with 65 additions and 70 deletions
@@ -11,12 +11,12 @@ import Ribbon from './Ribbon';
import SettingsDialog from './settings/SettingsDialog';
import Annotator from './annotator/Annotator';
interface BookGridProps {
interface BooksGridProps {
bookKeys: string[];
onCloseBook: (bookKey: string) => void;
}
const BookGrid: React.FC<BookGridProps> = ({ bookKeys, onCloseBook }) => {
const BooksGrid: React.FC<BooksGridProps> = ({ bookKeys, onCloseBook }) => {
const { getConfig, getProgress, getBookData, getViewState, getViewSettings } = useReaderStore();
const { isFontLayoutSettingsDialogOpen, setFontLayoutSettingsDialogOpen } = useReaderStore();
const gridTemplate = getGridTemplate(bookKeys.length, window.innerWidth / window.innerHeight);
@@ -78,4 +78,4 @@ const BookGrid: React.FC<BookGridProps> = ({ bookKeys, onCloseBook }) => {
);
};
export default BookGrid;
export default BooksGrid;
@@ -1,27 +1,48 @@
'use client';
import * as React from 'react';
import { useRouter } from 'next/navigation';
import { useRouter, useSearchParams } from 'next/navigation';
import { useEnv } from '@/context/EnvContext';
import { useReaderStore } from '@/store/readerStore';
import { SystemSettings } from '@/types/settings';
import { uniqueId } from '@/utils/misc';
import useBooksManager from '../hooks/useBooksManager';
import useBookShortcuts from '../hooks/useBookShortcuts';
import Spinner from '@/components/Spinner';
import SideBar from './sidebar/SideBar';
import useBooks from '../hooks/useBooks';
import BookGrid from './BookGrid';
import useBookShortcuts from '../hooks/useBookShortcuts';
import Notebook from './notebook/Notebook';
import BooksGrid from './BooksGrid';
const ReaderContent: React.FC<{ settings: SystemSettings }> = ({ settings }) => {
const router = useRouter();
const searchParams = useSearchParams();
const { envConfig } = useEnv();
const { bookKeys, dismissBook, getNextBookKey, openSplitView } = useBooks();
const { sideBarBookKey, getView, getConfig, setSideBarBookKey } = useReaderStore();
const { getBookData, getViewState, clearViewState, saveConfig, saveSettings } = useReaderStore();
const { bookKeys, dismissBook, getNextBookKey } = useBooksManager();
const { sideBarBookKey, getView, getConfig, saveConfig, saveSettings, setSideBarBookKey } =
useReaderStore();
const { setBookKeys, getBookData, initViewState, getViewState, clearViewState } =
useReaderStore();
useBookShortcuts({ sideBarBookKey, bookKeys, openSplitView, getNextBookKey });
useBookShortcuts({ sideBarBookKey, bookKeys });
React.useEffect(() => {
const initialIds = (searchParams.get('ids') || '').split(',').filter(Boolean);
const initialBookKeys = initialIds.map((id) => `${id}-${uniqueId()}`);
setBookKeys(initialBookKeys);
const uniqueIds = new Set<string>();
console.log('Initialize books', initialBookKeys);
initialBookKeys.forEach((key, index) => {
const id = key.split('-')[0]!;
const isPrimary = !uniqueIds.has(id);
uniqueIds.add(id);
if (!getViewState(key)) {
initViewState(envConfig, id, key, isPrimary);
if (index === 0) setSideBarBookKey(key);
}
});
}, []);
const saveConfigAndCloseBook = (bookKey: string) => {
getView(bookKey)?.close();
@@ -70,8 +91,8 @@ const ReaderContent: React.FC<{ settings: SystemSettings }> = ({ settings }) =>
return (
<div className='flex h-screen'>
<SideBar onGoToLibrary={handleCloseBooks} onOpenSplitView={openSplitView} />
<BookGrid bookKeys={bookKeys} onCloseBook={handleCloseBook} />
<SideBar onGoToLibrary={handleCloseBooks} />
<BooksGrid bookKeys={bookKeys} onCloseBook={handleCloseBook} />
<Notebook />
</div>
);
@@ -1,13 +1,14 @@
import React from 'react';
import useBooksManager from '../../hooks/useBooksManager';
interface BookMenuProps {
openSplitView: () => void;
setIsDropdownOpen?: (isOpen: boolean) => void;
}
const BookMenu: React.FC<BookMenuProps> = ({ openSplitView, setIsDropdownOpen }) => {
const BookMenu: React.FC<BookMenuProps> = ({ setIsDropdownOpen }) => {
const { openParallelView } = useBooksManager();
const handleOpenSplitView = () => {
openSplitView();
openParallelView();
setIsDropdownOpen?.(false);
};
const handleReloadPage = () => {
@@ -11,9 +11,8 @@ import BookMenu from './BookMenu';
const SidebarHeader: React.FC<{
isPinned: boolean;
onGoToLibrary: () => void;
onOpenSplitView: () => void;
handleTogglePin: () => void;
}> = ({ isPinned, onGoToLibrary, onOpenSplitView, handleTogglePin }) => {
}> = ({ isPinned, onGoToLibrary, handleTogglePin }) => {
const { isTrafficLightVisible } = useTrafficLight();
return (
<div
@@ -36,7 +35,7 @@ const SidebarHeader: React.FC<{
buttonClassName='btn btn-ghost h-8 min-h-8 w-8 p-0'
toggleButton={<MdOutlineMenu size={20} />}
>
<BookMenu openSplitView={onOpenSplitView} />
<BookMenu />
</Dropdown>
<div className='right-0 flex h-8 w-8 items-center justify-center'>
<button
@@ -15,8 +15,7 @@ const MAX_SIDEBAR_WIDTH = 0.45;
const SideBar: React.FC<{
onGoToLibrary: () => void;
onOpenSplitView: () => void;
}> = ({ onGoToLibrary, onOpenSplitView }) => {
}> = ({ onGoToLibrary }) => {
const { envConfig } = useEnv();
const { sideBarBookKey, settings } = useReaderStore();
const { saveSettings, getBookData } = useReaderStore();
@@ -75,7 +74,6 @@ const SideBar: React.FC<{
<SidebarHeader
isPinned={isSideBarPinned}
onGoToLibrary={onGoToLibrary}
onOpenSplitView={onOpenSplitView}
handleTogglePin={handleSideBarTogglePin}
/>
<div className='border-b px-3'>
@@ -1,21 +1,16 @@
import { useReaderStore } from '@/store/readerStore';
import useShortcuts from '@/hooks/useShortcuts';
import useBooksManager from './useBooksManager';
interface UseBookShortcutsProps {
sideBarBookKey: string | null;
bookKeys: string[];
openSplitView: () => void;
getNextBookKey: (bookKey: string) => string;
}
const useBookShortcuts = ({
sideBarBookKey,
bookKeys,
openSplitView,
getNextBookKey,
}: UseBookShortcutsProps) => {
const useBookShortcuts = ({ sideBarBookKey, bookKeys }: UseBookShortcutsProps) => {
const { getView, setSideBarBookKey, getViewSettings } = useReaderStore();
const { toggleSideBar, toggleNotebook } = useReaderStore();
const { getNextBookKey, openParallelView } = useBooksManager();
const viewSettings = getViewSettings(sideBarBookKey ?? '');
const fontSize = viewSettings?.defaultFontSize ?? 16;
const lineHeight = viewSettings?.lineHeight ?? 1.6;
@@ -47,7 +42,7 @@ const useBookShortcuts = ({
useShortcuts(
{
onOpenSplitView: openSplitView,
onOpenParallelView: openParallelView,
onSwitchSideBar: switchSideBar,
onToggleSideBar: toggleSideBar,
onToggleNotebook: toggleNotebook,
@@ -4,16 +4,12 @@ import { useEnv } from '@/context/EnvContext';
import { useReaderStore } from '@/store/readerStore';
import { uniqueId } from '@/utils/misc';
const useBooks = () => {
const { envConfig } = useEnv();
const searchParams = useSearchParams();
const useBooksManager = () => {
const router = useRouter();
const { sideBarBookKey, initViewState, getViewState, setSideBarBookKey } = useReaderStore();
const initialIds = (searchParams.get('ids') || '').split(',').filter(Boolean);
const [bookKeys, setBookKeys] = useState<string[]>(() => {
return initialIds.map((id) => `${id}-${uniqueId()}`);
});
const searchParams = useSearchParams();
const { envConfig } = useEnv();
const { bookKeys, sideBarBookKey } = useReaderStore();
const { setBookKeys, initViewState, setSideBarBookKey } = useReaderStore();
const [shouldUpdateSearchParams, setShouldUpdateSearchParams] = useState(false);
useEffect(() => {
@@ -32,22 +28,18 @@ const useBooks = () => {
const appendBook = (id: string, isPrimary: boolean) => {
const newKey = `${id}-${uniqueId()}`;
initViewState(envConfig, id, newKey, isPrimary);
setBookKeys((prevKeys) => {
if (!prevKeys.includes(newKey)) {
prevKeys.push(newKey);
}
return prevKeys;
});
if (!bookKeys.includes(newKey)) {
const updatedKeys = [...bookKeys, newKey];
setBookKeys(updatedKeys);
}
setSideBarBookKey(newKey);
setShouldUpdateSearchParams(true);
};
// Close a book and sync with bookKeys and URL
const dismissBook = (bookKey: string) => {
setBookKeys((prevKeys) => {
const updatedKeys = prevKeys.filter((key) => key !== bookKey);
return updatedKeys;
});
const updatedKeys = bookKeys.filter((key) => key !== bookKey);
setBookKeys(updatedKeys);
setShouldUpdateSearchParams(true);
};
@@ -57,33 +49,18 @@ const useBooks = () => {
return bookKeys[nextIndex]!;
};
const openSplitView = () => {
const openParallelView = () => {
const sideBarBookId = sideBarBookKey?.split('-')[0];
if (sideBarBookId) appendBook(sideBarBookId, false);
};
// Initialize all book states on first load
useEffect(() => {
const uniqueIds = new Set<string>();
console.log('Initialize books', bookKeys);
bookKeys.forEach((key, index) => {
const id = key.split('-')[0]!;
const isPrimary = !uniqueIds.has(id);
uniqueIds.add(id);
if (!getViewState(key)) {
initViewState(envConfig, id, key, isPrimary);
if (index === 0) setSideBarBookKey(key);
}
});
}, []);
return {
bookKeys,
appendBook,
dismissBook,
getNextBookKey,
openSplitView,
openParallelView,
};
};
export default useBooks;
export default useBooksManager;
+2 -2
View File
@@ -2,7 +2,7 @@ export interface ShortcutConfig {
onSwitchSideBar: string[];
onToggleSideBar: string[];
onToggleNotebook: string[];
onOpenSplitView: string[];
onOpenParallelView: string[];
onReloadPage: string[];
onGoLeft: string[];
onGoRight: string[];
@@ -14,7 +14,7 @@ const DEFAULT_SHORTCUTS: ShortcutConfig = {
onSwitchSideBar: ['ctrl+Tab', 'opt+Tab', 'alt+Tab'],
onToggleSideBar: ['s'],
onToggleNotebook: ['n'],
onOpenSplitView: ['shift+p'],
onOpenParallelView: ['shift+p'],
onReloadPage: ['shift+r'],
onGoLeft: ['ArrowLeft', 'PageUp', 'h'],
onGoRight: ['ArrowRight', 'PageDown', 'l'],
@@ -48,8 +48,10 @@ interface ReaderStore {
booksData: { [id: string]: BookData };
viewStates: { [key: string]: ViewState };
bookKeys: string[];
hoveredBookKey: string | null;
sideBarBookKey: string | null;
setBookKeys: (keys: string[]) => void;
setHoveredBookKey: (key: string) => void;
setSideBarBookKey: (key: string) => void;
@@ -123,8 +125,10 @@ export const useReaderStore = create<ReaderStore>((set, get) => ({
booksData: {},
viewStates: {},
bookKeys: [],
hoveredBookKey: null,
sideBarBookKey: null,
setBookKeys: (keys: string[]) => set({ bookKeys: keys }),
setHoveredBookKey: (key: string) => set({ hoveredBookKey: key }),
setSideBarBookKey: (key: string) => set({ sideBarBookKey: key }),