New reading surface with paper/sepia/dark themes, slim top and bottom bars, and sheets for navigation, search, settings, audio and per-verse study tools. Plan progress is built into the reader. Page-flip mode removed. ESV added via the server-side proxy (ESV_API_KEY). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9e8420a1ae
commit
9e722a296d
17 files changed
+903
-791
No files matched your search
@@ -0,0 +1,51 @@
|
||||
// Top and bottom chrome for the reader. Everything stays one tap away; focus
|
||||
// mode hides both.
|
||||
import { ChevronLeft, ChevronRight, ChevronDown, SearchIcon, LinkIcon, PenIcon, HeadphonesIcon, FocusIcon, CheckIcon } from './icons.jsx';
|
||||
import { BookmarkIcon } from '../../utils/bibleUtils.jsx';
|
||||
|
||||
const iconBtn = 'flex h-9 w-9 items-center justify-center rounded-lg text-[var(--r-sub)] transition hover:bg-black/5 disabled:opacity-30 disabled:hover:bg-transparent';
|
||||
|
||||
export function TopBar({ title, onBack, onOpenNavigator, onSearch, onBookmarks, bookmarkCount, onSettings }) {
|
||||
return (
|
||||
<div className="sticky top-0 z-30 border-b border-[var(--r-line)] bg-[var(--r-bar)] font-sans">
|
||||
<div className="mx-auto flex h-12 max-w-4xl items-center gap-1 px-2">
|
||||
<button type="button" onClick={onBack} className={iconBtn} aria-label="Back to studies"><ChevronLeft /></button>
|
||||
<button type="button" onClick={onOpenNavigator}
|
||||
className="mx-auto flex min-w-0 items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium text-[var(--r-text)] hover:bg-black/5">
|
||||
<span className="truncate">{title}</span><ChevronDown />
|
||||
</button>
|
||||
<button type="button" onClick={onSearch} className={iconBtn} aria-label="Search"><SearchIcon /></button>
|
||||
<button type="button" onClick={onBookmarks} className={`${iconBtn} relative ${bookmarkCount ? 'text-[var(--r-accent)]' : ''}`} aria-label="Bookmarks">
|
||||
<BookmarkIcon filled={bookmarkCount > 0} />
|
||||
</button>
|
||||
<button type="button" onClick={onSettings} className={`${iconBtn} w-10 text-sm font-medium`} aria-label="Reading settings">Aa</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function BottomBar({
|
||||
onPrev, onNext, prevDisabled, nextDisabled,
|
||||
onAudio, audioActive, onPen, onCrossRefs, crossRefsOn, onFocus, primary,
|
||||
}) {
|
||||
const active = 'text-[var(--r-accent)]';
|
||||
return (
|
||||
<div className="fixed inset-x-0 bottom-0 z-30 border-t border-[var(--r-line)] bg-[var(--r-bar)] pb-[env(safe-area-inset-bottom)] font-sans">
|
||||
<div className="mx-auto flex h-14 max-w-4xl items-center gap-0.5 px-2">
|
||||
<button type="button" onClick={onPrev} disabled={prevDisabled} className={iconBtn} aria-label="Previous chapter"><ChevronLeft /></button>
|
||||
<button type="button" onClick={onAudio} className={`${iconBtn} ${audioActive ? active : ''}`} aria-label="Listen"><HeadphonesIcon /></button>
|
||||
<button type="button" onClick={onPen} className={iconBtn} aria-label="Draw notes"><PenIcon /></button>
|
||||
<button type="button" onClick={onCrossRefs} className={`${iconBtn} ${crossRefsOn ? active : ''}`} aria-label="Show cross-references under verses"><LinkIcon /></button>
|
||||
<button type="button" onClick={onFocus} className={iconBtn} aria-label="Hide controls"><FocusIcon /></button>
|
||||
<div className="mx-auto" />
|
||||
{primary && (
|
||||
<button type="button" onClick={primary.onClick}
|
||||
className="mr-1 flex items-center gap-1.5 rounded-full bg-[var(--r-accent)] px-4 py-2 text-xs font-medium text-[var(--r-on)]">
|
||||
{primary.done ? null : <CheckIcon />}{primary.label}
|
||||
</button>
|
||||
)}
|
||||
<button type="button" onClick={onNext} disabled={nextDisabled} className={iconBtn} aria-label="Next chapter"><ChevronRight /></button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user