forked from akai/readest
Refactor useBooksManager and make it reusable
This commit is contained in:
+3
-3
@@ -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,
|
||||
|
||||
+14
-37
@@ -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,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 }),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user