Add Outline stage, parallel reading, offline saves, backup, sync-conflict handling and more
Study - New Outline stage (hierarchical I./A./1. points, linked to chunks, in all exports); the chunk stage is now "Chunks" - Home cards: passages shown as ranges, tags capped with "+N more" Reader - Side-by-side translations and a Compare tab per verse - Typeface, line spacing, verse-number settings; text and column scale with the screen - Highlights/bookmarks sheet with named colours (synced); BSB footnote spacing fix - Cmd-K palette (passages, studies, notes, marks), keyboard shortcuts and "?" help Flow and safety - Toasts with Undo replace most confirm()/alert() - Back/Forward move between pages - Server refuses saves over a newer copy (409); keep-mine / use-other banner; opening a study no longer re-stamps it - Latest chapter request wins when flipping quickly Offline and data - Save books, plan days or a whole BSB/NET for offline - Service worker fixes: helloao /api/ URLs were skipped and responses cloned too late - Settings: download/restore a full backup Accessibility - Sheets trap focus and close on Escape, skip link, focus ring, reduced motion, theme contrast raised to 4.5:1 (with a test) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1edbd364ea
commit
d13f55faf7
65 files changed
+2947
-208
No files matched your search
@@ -0,0 +1,63 @@
|
||||
// The "?" cheat sheet: every keyboard shortcut for the page you are on, plus the ones that work everywhere.
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useApp } from '../context/AppContext.js';
|
||||
import { themeVars } from './reader/readerThemes.js';
|
||||
|
||||
const GLOBAL = [
|
||||
['⌘K / Ctrl K', 'Search and go to a passage'],
|
||||
['?', 'Show this list'],
|
||||
['Esc', 'Close whatever is open'],
|
||||
];
|
||||
const BY_PAGE = {
|
||||
reader: [
|
||||
['← →', 'Previous / next chapter'],
|
||||
['/', 'Search this chapter or the whole Bible'],
|
||||
['G', 'Pick a book and chapter'],
|
||||
['B', 'Bookmark the selected verse'],
|
||||
[',', 'Reading settings'],
|
||||
['F', 'Hide or show the controls'],
|
||||
],
|
||||
study: [
|
||||
['← →', 'Previous / next chunk'],
|
||||
],
|
||||
};
|
||||
|
||||
export default function ShortcutsHelp({ onClose }) {
|
||||
const { readerTheme, currentPage } = useApp();
|
||||
const closeRef = useRef(null);
|
||||
useEffect(() => {
|
||||
const from = document.activeElement;
|
||||
closeRef.current?.focus();
|
||||
const onKey = (e) => { if (e.key === 'Escape' || e.key === '?') { e.preventDefault(); e.stopPropagation(); onClose(); } };
|
||||
document.addEventListener('keydown', onKey, true);
|
||||
return () => { document.removeEventListener('keydown', onKey, true); if (from instanceof HTMLElement && document.contains(from)) from.focus({ preventScroll: true }); };
|
||||
}, [onClose]);
|
||||
|
||||
const page = BY_PAGE[currentPage] ?? [];
|
||||
const section = (title, rows) => (
|
||||
<div className="mb-4 last:mb-0">
|
||||
<h3 className="mb-1.5 text-[11px] uppercase tracking-wide text-[var(--r-sub)]">{title}</h3>
|
||||
<dl className="space-y-1.5">
|
||||
{rows.map(([keys, what]) => (
|
||||
<div key={keys} className="flex items-center justify-between gap-4 text-sm">
|
||||
<dt><kbd className="rounded-md border border-[var(--r-line)] bg-[var(--r-bg)] px-2 py-0.5 font-mono text-xs">{keys}</kbd></dt>
|
||||
<dd className="text-right text-[var(--r-sub)]">{what}</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={themeVars(readerTheme)} className="fixed inset-0 z-[90] flex items-center justify-center bg-black/40 px-3 font-sans" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
|
||||
<div role="dialog" aria-modal="true" aria-label="Keyboard shortcuts" className="max-h-[80vh] w-full max-w-sm overflow-y-auto rounded-2xl border border-[var(--r-line)] bg-[var(--r-bar)] p-5 text-[var(--r-text)] shadow-2xl">
|
||||
<div className="mb-3 flex items-center justify-between">
|
||||
<h2 className="text-base font-medium">Keyboard shortcuts</h2>
|
||||
<button ref={closeRef} type="button" onClick={onClose} className="rounded-lg px-2 py-1 text-sm text-[var(--r-sub)] hover:bg-black/5">Close</button>
|
||||
</div>
|
||||
{page.length > 0 && section(currentPage === 'reader' ? 'In the Bible' : 'In this study', page)}
|
||||
{section('Everywhere', GLOBAL)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user