Spaces:
Running
Running
fix: reset totalPages to 0 on volume change to prevent stale totalPages capping target page number
8a30eb3 | import { create } from 'zustand'; | |
| // ββ Reader Store β navigation & content only ββββββββββββββββββββββ | |
| interface ReaderState { | |
| currentVolume: number; // volume_number (NOT db id) | |
| currentPage: number; | |
| currentContent: string; | |
| totalPages: number; | |
| sectionTitle: string; | |
| volumeTitle: string; | |
| highlightQuery: string; // ΰΈΰΈ³ΰΈΰΉΰΈΰΈ«ΰΈ²ΰΈΰΈ΅ΰΉΰΈΰΉΰΈΰΈΰΈΰΈ²ΰΈ£ highlight ΰΈΰΈ reader | |
| setVolume: (vol: number) => void; | |
| setPage: (page: number) => void; | |
| setCurrentContent: (content: string) => void; | |
| setTotalPages: (total: number) => void; | |
| setSectionTitle: (title: string) => void; | |
| setVolumeTitle: (title: string) => void; | |
| setHighlightQuery: (q: string) => void; | |
| prevPage: () => void; | |
| nextPage: () => void; | |
| } | |
| export const useReaderStore = create<ReaderState>((set) => ({ | |
| currentVolume: 1, | |
| currentPage: 1, | |
| currentContent: '', | |
| totalPages: 0, | |
| sectionTitle: '', | |
| volumeTitle: '', | |
| highlightQuery: '', | |
| setVolume: (vol) => set({ currentVolume: vol, currentPage: 1, totalPages: 0 }), | |
| setPage: (page) => set((s) => ({ currentPage: Math.max(1, Math.min(page, s.totalPages || 9999)) })), | |
| setCurrentContent: (content) => set({ currentContent: content }), | |
| setTotalPages: (total) => set({ totalPages: total }), | |
| setSectionTitle: (title) => set({ sectionTitle: title }), | |
| setVolumeTitle: (title) => set({ volumeTitle: title }), | |
| setHighlightQuery: (q) => set({ highlightQuery: q }), | |
| prevPage: () => set((s) => ({ currentPage: Math.max(1, s.currentPage - 1), highlightQuery: '' })), | |
| nextPage: () => set((s) => ({ currentPage: Math.min(s.totalPages || 9999, s.currentPage + 1), highlightQuery: '' })), | |
| })); | |
| // ββ Theme Store β fontSize & theme as single source of truth ββββββ | |
| type Theme = 'dark' | 'light' | 'classic'; | |
| const THEME_CYCLE: Theme[] = ['dark', 'light', 'classic']; | |
| interface ThemeState { | |
| theme: Theme; | |
| fontSize: number; // 12β36px | |
| setTheme: (t: Theme) => void; | |
| cycleTheme: () => void; | |
| increaseFontSize: () => void; | |
| decreaseFontSize: () => void; | |
| } | |
| export const useThemeStore = create<ThemeState>((set, get) => ({ | |
| theme: 'dark', | |
| fontSize: 18, | |
| setTheme: (t) => set({ theme: t }), | |
| cycleTheme: () => { | |
| const idx = THEME_CYCLE.indexOf(get().theme); | |
| set({ theme: THEME_CYCLE[(idx + 1) % THEME_CYCLE.length] }); | |
| }, | |
| increaseFontSize: () => set((s) => ({ fontSize: Math.min(s.fontSize + 2, 36) })), | |
| decreaseFontSize: () => set((s) => ({ fontSize: Math.max(s.fontSize - 2, 12) })), | |
| })); | |
| // ββ UI Store β nav drawer & tab state βββββββββββββββββββββββββββββ | |
| interface UIState { | |
| isNavOpen: boolean; | |
| activeTab: 'toc' | 'search' | 'overview'; | |
| toggleNav: () => void; | |
| setNavOpen: (open: boolean) => void; | |
| setActiveTab: (tab: 'toc' | 'search' | 'overview') => void; | |
| } | |
| export const useUIStore = create<UIState>((set) => ({ | |
| isNavOpen: true, | |
| activeTab: 'toc', | |
| toggleNav: () => set((s) => ({ isNavOpen: !s.isNavOpen })), | |
| setNavOpen: (open) => set({ isNavOpen: open }), | |
| setActiveTab: (tab) => set({ activeTab: tab }), | |
| })); | |