mirror of
https://github.com/readest/readest.git
synced 2026-05-19 07:53:58 +00:00
Custom fonts vanished from the Font panel after an app restart unless a book was opened first. The custom-font store is hydrated only by the reader's FoliateViewer (on book open) or by useReplicaPull (gated on a signed-in user), so opening Settings straight from the library left the store empty. Add a useCustomFonts hook that loads persisted custom fonts on mount, unconditional of auth or book state, and mount it on the library page. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d2ff47029c
commit
2d30868d23
3 changed files with 90 additions and 0 deletions
56
apps/readest-app/src/__tests__/hooks/useCustomFonts.test.tsx
Normal file
56
apps/readest-app/src/__tests__/hooks/useCustomFonts.test.tsx
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
|
||||
import { cleanup, renderHook } from '@testing-library/react';
|
||||
|
||||
const loadCustomFontsSpy = vi.fn<(...args: unknown[]) => Promise<void>>(async () => {});
|
||||
|
||||
let envValue: { envConfig: unknown; appService: unknown } = {
|
||||
envConfig: { name: 'env' },
|
||||
appService: { name: 'svc' },
|
||||
};
|
||||
let settingsValue: { settings: { customFonts?: unknown[] } } = {
|
||||
settings: { customFonts: [] },
|
||||
};
|
||||
|
||||
vi.mock('@/context/EnvContext', () => ({
|
||||
useEnv: () => envValue,
|
||||
}));
|
||||
|
||||
vi.mock('@/store/settingsStore', () => ({
|
||||
useSettingsStore: () => settingsValue,
|
||||
}));
|
||||
|
||||
vi.mock('@/store/customFontStore', () => ({
|
||||
useCustomFontStore: () => ({ loadCustomFonts: loadCustomFontsSpy }),
|
||||
}));
|
||||
|
||||
import { useCustomFonts } from '@/hooks/useCustomFonts';
|
||||
|
||||
beforeEach(() => {
|
||||
loadCustomFontsSpy.mockClear();
|
||||
envValue = { envConfig: { name: 'env' }, appService: { name: 'svc' } };
|
||||
settingsValue = { settings: { customFonts: [] } };
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
describe('useCustomFonts', () => {
|
||||
test('hydrates the custom font store on mount', () => {
|
||||
renderHook(() => useCustomFonts());
|
||||
expect(loadCustomFontsSpy).toHaveBeenCalledTimes(1);
|
||||
expect(loadCustomFontsSpy).toHaveBeenCalledWith(envValue.envConfig);
|
||||
});
|
||||
|
||||
test('waits for the app service before hydrating', () => {
|
||||
envValue = { envConfig: { name: 'env' }, appService: null };
|
||||
renderHook(() => useCustomFonts());
|
||||
expect(loadCustomFontsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('skips hydration when settings carry no customFonts field', () => {
|
||||
settingsValue = { settings: {} };
|
||||
renderHook(() => useCustomFonts());
|
||||
expect(loadCustomFontsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
@ -81,6 +81,7 @@ import LibraryEmptyState from './components/LibraryEmptyState';
|
|||
import GroupHeader from './components/GroupHeader';
|
||||
import useShortcuts from '@/hooks/useShortcuts';
|
||||
import { useReplicaPull } from '@/hooks/useReplicaPull';
|
||||
import { useCustomFonts } from '@/hooks/useCustomFonts';
|
||||
import DropIndicator from '@/components/DropIndicator';
|
||||
import SettingsDialog from '@/components/settings/SettingsDialog';
|
||||
import ModalPortal from '@/components/ModalPortal';
|
||||
|
|
@ -124,6 +125,11 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP
|
|||
useReplicaPull({
|
||||
kinds: ['dictionary', 'font', 'texture', 'opds_catalog', 'settings'],
|
||||
});
|
||||
// Hydrate the custom-font store from persisted settings so the Font
|
||||
// panel sees imported fonts even when opened straight from the
|
||||
// library — the replica pull above is auth-gated and the reader's
|
||||
// FoliateViewer hydration never runs without a book open.
|
||||
useCustomFonts();
|
||||
const [showCatalogManager, setShowCatalogManager] = useState(
|
||||
searchParams?.get('opds') === 'true',
|
||||
);
|
||||
|
|
|
|||
28
apps/readest-app/src/hooks/useCustomFonts.ts
Normal file
28
apps/readest-app/src/hooks/useCustomFonts.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useCustomFontStore } from '@/store/customFontStore';
|
||||
|
||||
/**
|
||||
* Hydrate the custom-font store from persisted `settings.customFonts`.
|
||||
*
|
||||
* The reader hydrates the store inside FoliateViewer when a book opens,
|
||||
* and `useReplicaPull` hydrates it during a sync — but that pull is
|
||||
* gated on a signed-in user. Without this hook, opening Settings
|
||||
* straight from the library (no book opened, no account) leaves the
|
||||
* store empty, so imported custom fonts vanish from the Font panel
|
||||
* after an app restart until a book is opened. Mount this on the
|
||||
* library page so the panel always sees the persisted fonts.
|
||||
*/
|
||||
export const useCustomFonts = () => {
|
||||
const { envConfig, appService } = useEnv();
|
||||
const { settings } = useSettingsStore();
|
||||
const { loadCustomFonts } = useCustomFontStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (!appService) return;
|
||||
if (!settings?.customFonts) return;
|
||||
void loadCustomFonts(envConfig);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [appService, settings?.customFonts, envConfig]);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue