- Study cards say whether the Bible text works offline, with a button to save the missing book (notes are always kept on the device). - Each note keeps its last 12 versions with Restore (History under each note). - Keyboard-only study: 1/2/3 write in Observe/Interpret/Apply, C/W/X/P switch resource tabs, V compares, Esc leaves a note box; listed under "?". - Export > Import notes: bring Word/Markdown/text notes into the matching chunks without overwriting anything; can mark them as not your own. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
71 lines
3.2 KiB
React
71 lines
3.2 KiB
React
// 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'],
|
||
['C', 'Compare translations'],
|
||
['M', 'Map this chapter’s cross-references (needs IQ Bible)'],
|
||
['H', 'Your highlights'],
|
||
[',', 'Reading settings'],
|
||
['F', 'Hide or show the controls'],
|
||
],
|
||
study: [
|
||
['← →', 'Previous / next chunk'],
|
||
['1 2 3', 'Write in Observe / Interpret / Apply'],
|
||
['Esc', 'Leave a note box (then keys work again)'],
|
||
['C W X P', 'Commentary / Word study / Cross-refs / People & places'],
|
||
['V', 'Compare passages or translations'],
|
||
],
|
||
};
|
||
|
||
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-[80dvh] 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>
|
||
);
|
||
}
|