diff --git a/apps/readest-app/src/app/reader/components/HeaderBar.tsx b/apps/readest-app/src/app/reader/components/HeaderBar.tsx index 963aabc8..19838da0 100644 --- a/apps/readest-app/src/app/reader/components/HeaderBar.tsx +++ b/apps/readest-app/src/app/reader/components/HeaderBar.tsx @@ -11,6 +11,7 @@ import Dropdown from '@/components/Dropdown'; import SidebarToggler from './SidebarToggler'; import BookmarkToggler from './BookmarkToggler'; import NotebookToggler from './NotebookToggler'; +import SettingsToggler from './SettingsToggler'; import ViewMenu from './ViewMenu'; interface HeaderBarProps { @@ -57,16 +58,17 @@ const HeaderBar: React.FC = ({ onMouseEnter={() => setHoveredBookKey(bookKey)} onMouseLeave={() => setHoveredBookKey('')} > -
+
-
+

{bookTitle}

-
+
+ = ({ bookKey }) => { + ); +}; + +export default SettingsToggler; diff --git a/apps/readest-app/src/app/reader/components/ViewMenu.tsx b/apps/readest-app/src/app/reader/components/ViewMenu.tsx index 4f69d7bd..dc272fcc 100644 --- a/apps/readest-app/src/app/reader/components/ViewMenu.tsx +++ b/apps/readest-app/src/app/reader/components/ViewMenu.tsx @@ -92,7 +92,7 @@ const ViewMenu: React.FC = ({ + diff --git a/apps/readest-app/src/app/reader/components/notebook/Notebook.tsx b/apps/readest-app/src/app/reader/components/notebook/Notebook.tsx index 3a5e424b..7191a363 100644 --- a/apps/readest-app/src/app/reader/components/notebook/Notebook.tsx +++ b/apps/readest-app/src/app/reader/components/notebook/Notebook.tsx @@ -8,13 +8,14 @@ import { useSidebarStore } from '@/store/sidebarStore'; import { useNotebookStore } from '@/store/notebookStore'; import { useTranslation } from '@/hooks/useTranslation'; import { useEnv } from '@/context/EnvContext'; -import useDragBar from '../../hooks/useDragBar'; -import NotebookHeader from './Header'; -import NoteEditor from './NoteEditor'; import { TextSelection } from '@/utils/sel'; import { BookNote } from '@/types/book'; import { uniqueId } from '@/utils/misc'; +import { eventDispatcher } from '@/utils/event'; +import useDragBar from '../../hooks/useDragBar'; import BooknoteItem from '../sidebar/BooknoteItem'; +import NotebookHeader from './Header'; +import NoteEditor from './NoteEditor'; const MIN_NOTEBOOK_WIDTH = 0.15; const MAX_NOTEBOOK_WIDTH = 0.45; @@ -31,10 +32,23 @@ const Notebook: React.FC = ({}) => { const { setNotebookWidth, setNotebookVisible, toggleNotebookPin } = useNotebookStore(); const { setNotebookNewAnnotation, setNotebookEditAnnotation } = useNotebookStore(); + const onNavigateEvent = async () => { + const pinButton = document.querySelector('.sidebar-pin-btn'); + const isPinButtonHidden = !pinButton || window.getComputedStyle(pinButton).display === 'none'; + if (isPinButtonHidden) { + setNotebookVisible(false); + } + }; + useEffect(() => { setNotebookWidth(settings.globalReadSettings.notebookWidth); setNotebookPin(settings.globalReadSettings.isNotebookPinned); setNotebookVisible(settings.globalReadSettings.isNotebookPinned); + + eventDispatcher.on('navigate', onNavigateEvent); + return () => { + eventDispatcher.off('navigate', onNavigateEvent); + }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -135,11 +149,23 @@ const Notebook: React.FC = ({}) => { position: isNotebookPinned ? 'relative' : 'absolute', }} > +
- + setNotebookVisible(false)} + handleTogglePin={handleTogglePin} + />
{excerptNotes.length > 0 &&

{_('Excerpts')}

}
    diff --git a/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx b/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx index 0b97ceb9..9b92f5b1 100644 --- a/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx +++ b/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx @@ -1,3 +1,4 @@ +import clsx from 'clsx'; import React, { useEffect, useState } from 'react'; import { BookConfig } from '@/types/book'; import { useSettingsStore } from '@/store/settingsStore'; @@ -18,6 +19,12 @@ import MiscPanel from './MiscPanel'; type SettingsPanelType = 'Font' | 'Layout' | 'Color' | 'Misc'; +type TabConfig = { + tab: SettingsPanelType; + icon: React.ElementType; + label: string; +}; + const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ bookKey }) => { const _ = useTranslation(); const [activePanel, setActivePanel] = useState('Font'); @@ -37,39 +44,47 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + const tabConfig = [ + { + tab: 'Font', + icon: RiFontSize, + label: _('Font'), + }, + { + tab: 'Layout', + icon: RiDashboardLine, + label: _('Layout'), + }, + { + tab: 'Color', + icon: VscSymbolColor, + label: _('Color'), + }, + { + tab: 'Misc', + icon: IoAccessibilityOutline, + label: _('Misc'), + }, + ] as TabConfig[]; + return ( - -
    + +
    -
    - - - - +
    + {tabConfig.map(({ tab, icon: Icon, label }) => ( + + ))}
    void; } -const BookMenu: React.FC = ({ setIsDropdownOpen }) => { +const BookMenu: React.FC = ({ menuClassName, setIsDropdownOpen }) => { const _ = useTranslation(); const { library } = useLibraryStore(); const { openParallelView } = useBooksManager(); @@ -39,7 +41,10 @@ const BookMenu: React.FC = ({ setIsDropdownOpen }) => { return (
      diff --git a/apps/readest-app/src/app/reader/components/sidebar/BooknoteItem.tsx b/apps/readest-app/src/app/reader/components/sidebar/BooknoteItem.tsx index f5ef3944..bf088f01 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/BooknoteItem.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/BooknoteItem.tsx @@ -9,6 +9,7 @@ import { useNotebookStore } from '@/store/notebookStore'; import { useBookDataStore } from '@/store/bookDataStore'; import { useTranslation } from '@/hooks/useTranslation'; import useScrollToItem from '../../hooks/useScrollToItem'; +import { eventDispatcher } from '@/utils/event'; interface BooknoteItemProps { bookKey: string; @@ -29,6 +30,8 @@ const BooknoteItem: React.FC = ({ bookKey, item }) => { const handleClickItem = (event: React.MouseEvent) => { event.preventDefault(); + eventDispatcher.dispatch('navigate', { bookKey, cfi }); + getView(bookKey)?.goTo(cfi); if (note) { setNotebookVisible(true); diff --git a/apps/readest-app/src/app/reader/components/sidebar/Header.tsx b/apps/readest-app/src/app/reader/components/sidebar/Header.tsx index edacb5c2..1ea5952d 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/Header.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/Header.tsx @@ -12,9 +12,10 @@ const SidebarHeader: React.FC<{ isPinned: boolean; isSearchBarVisible: boolean; onGoToLibrary: () => void; + onClose: () => void; onTogglePin: () => void; onToggleSearchBar: () => void; -}> = ({ isPinned, isSearchBarVisible, onGoToLibrary, onTogglePin, onToggleSearchBar }) => { +}> = ({ isPinned, isSearchBarVisible, onGoToLibrary, onClose, onTogglePin, onToggleSearchBar }) => { const { isTrafficLightVisible } = useTrafficLight(); return (
      } > @@ -48,10 +53,24 @@ const SidebarHeader: React.FC<{
      +
    diff --git a/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx b/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx index 37f6aa85..c1a86498 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx @@ -166,7 +166,7 @@ const SearchBar: React.FC = ({ className='w-full bg-transparent p-2 font-sans text-sm font-light focus:outline-none' /> -
    +
    void; } +interface OptionProps { + label: string; + isActive: boolean; + onClick: () => void; +} + +const Option: React.FC = ({ label, isActive, onClick }) => ( + +); + const SearchOptions: React.FC = ({ searchConfig, onSearchConfigChanged, setIsDropdownOpen, }) => { const _ = useTranslation(); - const handleSetScope = () => { - onSearchConfigChanged({ - ...searchConfig, - scope: searchConfig.scope === 'book' ? 'section' : 'book', - }); - setIsDropdownOpen?.(false); - }; - const handleSetMatchCase = () => { - onSearchConfigChanged({ ...searchConfig, matchCase: !searchConfig.matchCase }); - setIsDropdownOpen?.(false); - }; - const handleSetMatchWholeWords = () => { - onSearchConfigChanged({ ...searchConfig, matchWholeWords: !searchConfig.matchWholeWords }); - setIsDropdownOpen?.(false); - }; - const handleSetMatchDiacritics = () => { - onSearchConfigChanged({ ...searchConfig, matchDiacritics: !searchConfig.matchDiacritics }); + const updateConfig = (key: keyof BookSearchConfig, value: boolean | string) => { + onSearchConfigChanged({ ...searchConfig, [key]: value }); setIsDropdownOpen?.(false); }; return (
    - - - - -
    - - - - - - +
    ); }; diff --git a/apps/readest-app/src/app/reader/components/sidebar/SideBar.tsx b/apps/readest-app/src/app/reader/components/sidebar/SideBar.tsx index 92ac6ccd..2dbe6527 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/SideBar.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/SideBar.tsx @@ -38,7 +38,7 @@ const SideBar: React.FC<{ handleSideBarTogglePin, } = useSidebar( settings.globalReadSettings.sideBarWidth, - settings.globalReadSettings.isSideBarPinned, + window.innerWidth >= 640 ? settings.globalReadSettings.isSideBarPinned : false, ); const onSearchEvent = async (event: CustomEvent) => { @@ -48,10 +48,20 @@ const SideBar: React.FC<{ setSearchTerm(term); }; + const onNavigateEvent = async () => { + const pinButton = document.querySelector('.sidebar-pin-btn'); + const isPinButtonHidden = !pinButton || window.getComputedStyle(pinButton).display === 'none'; + if (isPinButtonHidden) { + setSideBarVisible(false); + } + }; + useEffect(() => { eventDispatcher.on('search', onSearchEvent); + eventDispatcher.on('navigate', onNavigateEvent); return () => { eventDispatcher.off('search', onSearchEvent); + eventDispatcher.off('navigate', onNavigateEvent); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -79,6 +89,7 @@ const SideBar: React.FC<{ useShortcuts({ onToggleSearchBar: handleToggleSearchBar }, [sideBarBookKey]); const handleSearchResultClick = (cfi: string) => { + onNavigateEvent(); getView(sideBarBookKey)?.goTo(cfi); }; @@ -104,11 +115,20 @@ const SideBar: React.FC<{ position: isSideBarPinned ? 'relative' : 'absolute', }} > +
    setSideBarVisible(false)} onTogglePin={handleSideBarTogglePin} onToggleSearchBar={handleToggleSearchBar} /> diff --git a/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx b/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx index 2fe8380c..ad492857 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx @@ -1,3 +1,4 @@ +import clsx from 'clsx'; import React, { useEffect, useRef, useState } from 'react'; import { TOCItem } from '@/libs/document'; @@ -5,7 +6,7 @@ import { useReaderStore } from '@/store/readerStore'; import { useSidebarStore } from '@/store/sidebarStore'; import { findParentPath } from '@/utils/toc'; import { getContentMd5 } from '@/utils/misc'; -import clsx from 'clsx'; +import { eventDispatcher } from '@/utils/event'; const createExpanderIcon = (isExpanded: boolean) => { return ( @@ -43,6 +44,7 @@ const TOCItemView: React.FC<{ const handleClickItem = (event: React.MouseEvent) => { event.preventDefault(); + eventDispatcher.dispatch('navigate', { bookKey, href: item.href }); if (item.href) { getView(bookKey)?.goTo(item.href); } diff --git a/apps/readest-app/src/components/Button.tsx b/apps/readest-app/src/components/Button.tsx index b11c0d7b..f90c11b6 100644 --- a/apps/readest-app/src/components/Button.tsx +++ b/apps/readest-app/src/components/Button.tsx @@ -20,14 +20,14 @@ const Button: React.FC = ({ }) => { return (