Preferences in Settings and a home page the user chooses
Build and Push Docker Image / build-and-push (push) Failing after 20s
Build and Push Docker Image / build-and-push (push) Failing after 20s
Settings gets a Preferences section: theme, default Bible, the Bible new reading plans start in, verse layout, commentary, text size, reading width, audio narrator (the last three stay per device; text size and narrator are now remembered). A Home page setting (My Studies, Bible Reader or Reading Plans) decides where the app opens and where every Home button goes; already being there means My Studies. Back arrows are labelled Home. Tests cover every page leading back. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
760c1e568b
commit
8c4f54e033
15 files changed
+401
-23
No files matched your search
@@ -73,7 +73,46 @@ export function useBibleReader(currentPage, translationOverride = null) {
|
||||
const [readerInterlinearLoading, setReaderInterlinearLoading] = useState(false);
|
||||
const [readerSelectedVerse, setReaderSelectedVerse] = useState(null); // verse number with open interlinear panel
|
||||
const _readerInterlinearCacheRef = useRef({});
|
||||
const [readerFontSize, setReaderFontSize] = useState(1); // em multiplier: 0.875 | 1 | 1.125 | 1.25
|
||||
// Text size and reading width are per-device (a phone and a tablet want different ones)
|
||||
const [readerFontSize, setReaderFontSizeState] = useState(() => {
|
||||
try {
|
||||
const n = Number(localStorage.getItem('reader-font-size'));
|
||||
return [0.875, 1, 1.125, 1.25, 1.5].includes(n) ? n : 1;
|
||||
} catch { return 1; }
|
||||
}); // em multiplier: 0.875 | 1 | 1.125 | 1.25 | 1.5
|
||||
const setReaderFontSize = (n) => {
|
||||
setReaderFontSizeState(n);
|
||||
try { localStorage.setItem('reader-font-size', String(n)); } catch {}
|
||||
};
|
||||
const [readerWide, setReaderWideState] = useState(() => {
|
||||
try { return localStorage.getItem('reader-wide') === '1'; } catch { return false; }
|
||||
});
|
||||
const setReaderWide = (on) => {
|
||||
setReaderWideState(!!on);
|
||||
try { localStorage.setItem('reader-wide', on ? '1' : '0'); } catch {}
|
||||
};
|
||||
// The page the app opens to, and where every Home button goes: 'studies' | 'reader' | 'plans'
|
||||
const [startPagePref, setStartPagePrefState] = useState(() => {
|
||||
try {
|
||||
const saved = localStorage.getItem('start-page');
|
||||
return ['studies', 'reader', 'plans'].includes(saved) ? saved : 'studies';
|
||||
} catch { return 'studies'; }
|
||||
});
|
||||
const setStartPagePref = (id) => {
|
||||
setStartPagePrefState(id);
|
||||
try { localStorage.setItem('start-page', id); } catch {}
|
||||
};
|
||||
// Which Bible a newly started reading plan begins in: 'same' = whatever the default Bible is
|
||||
const [planTranslationPref, setPlanTranslationPrefState] = useState(() => {
|
||||
try {
|
||||
const saved = localStorage.getItem('plan-translation');
|
||||
return saved === 'same' || READER_TRANSLATIONS.some((t) => t.id === saved) ? saved : 'same';
|
||||
} catch { return 'same'; }
|
||||
});
|
||||
const setPlanTranslationPref = (id) => {
|
||||
setPlanTranslationPrefState(id);
|
||||
try { localStorage.setItem('plan-translation', id); } catch {}
|
||||
};
|
||||
const [readerBookmarks, setReaderBookmarks] = useState(() => {
|
||||
try { return JSON.parse(localStorage.getItem('reader-bookmarks') || '{}'); } catch { return {}; }
|
||||
});
|
||||
@@ -397,12 +436,15 @@ export function useBibleReader(currentPage, translationOverride = null) {
|
||||
const prefsSync = usePrefsSync({
|
||||
values: {
|
||||
theme: readerTheme, translation: baseTranslation, layout: readerLayout, commentarySource: readerCommentary,
|
||||
planTranslation: planTranslationPref, startPage: startPagePref,
|
||||
position: { book: readerBookAbbrev, chapter: readerChapter },
|
||||
},
|
||||
apply: (key, v) => {
|
||||
if (key === 'theme') { setReaderThemeState(v); try { localStorage.setItem('reader-theme', v); } catch {} }
|
||||
else if (key === 'translation') { setReaderTranslationState(v); try { localStorage.setItem('reader-translation', v); } catch {} }
|
||||
else if (key === 'layout') { setReaderLayoutState(v); try { localStorage.setItem('reader-layout', v); } catch {} }
|
||||
else if (key === 'startPage') { setStartPagePrefState(v); try { localStorage.setItem('start-page', v); } catch {} }
|
||||
else if (key === 'planTranslation') { setPlanTranslationPrefState(v); try { localStorage.setItem('plan-translation', v); } catch {} }
|
||||
else if (key === 'commentarySource') { setReaderCommentaryState(v); try { localStorage.setItem('reader-commentary', v); } catch {} }
|
||||
else if (key === 'position') { setReaderBookAbbrev(v.book); setReaderChapter(v.chapter); setReaderSelectedVerse(null); }
|
||||
},
|
||||
@@ -424,6 +466,9 @@ export function useBibleReader(currentPage, translationOverride = null) {
|
||||
readerInterlinear,
|
||||
readerSelectedVerse, setReaderSelectedVerse,
|
||||
readerFontSize, setReaderFontSize,
|
||||
readerWide, setReaderWide,
|
||||
planTranslationPref, setPlanTranslationPref,
|
||||
startPagePref, setStartPagePref,
|
||||
readerBookmarks, setReaderBookmarks,
|
||||
readerBookmarksPanelOpen, setReaderBookmarksPanelOpen,
|
||||
readerCrossRefs, setReaderCrossRefs,
|
||||
|
||||
Reference in new issue
Block a user