Build and Push Docker Image / build-and-push (push) Failing after 20s
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>
52 lines
3.3 KiB
React
52 lines
3.3 KiB
React
// 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>
|
|
);
|
|
}
|