feat(ui): back-to-library, export-only download button, save in book setup

This commit is contained in:
pj committed 2026-06-20 15:09:13 -04:00
1 parent 686c7768c7
commit e9669290ec
3 files changed
+30 -13

No files matched your search

+9 -6
View File
@@ -25,6 +25,7 @@ function PdfDock() {
const timer = useRef<ReturnType<typeof setTimeout>>(undefined);
useEffect(() => {
if (!book) return;
clearTimeout(timer.current);
setBusy(true);
timer.current = setTimeout(() => {
@@ -44,7 +45,7 @@ function PdfDock() {
<section className="dock">
<div className="dock-head">
<span className="label">Preview</span>
<span className="meta">{busy ? "updating…" : TRIM_LABEL[book.settings.trim]}</span>
<span className="meta">{busy ? "updating…" : TRIM_LABEL[book?.settings.trim ?? "6x9"]}</span>
</div>
{error ? (
<pre className="dock-error">{error}</pre>
@@ -58,19 +59,21 @@ function PdfDock() {
}
function HtmlDock() {
const chapters = useBook((s) => s.book.chapters);
const trim = useBook((s) => s.book.settings.trim);
const book = useBook((s) => s.book);
const activeChapterId = useBook((s) => s.activeChapterId);
const chapters = book?.chapters ?? [];
const idx = chapters.findIndex((c) => c.id === activeChapterId);
const chapter = chapters[idx];
const html = useMemo(() => generateHTML(chapter.content, editorExtensions), [chapter.content]);
const chapter = chapters[idx] ?? chapters[0];
const html = useMemo(() => (chapter ? generateHTML(chapter.content, editorExtensions) : ""), [chapter]);
if (!book || !chapter) return null;
return (
<section className="dock">
<div className="dock-head">
<span className="label">Preview</span>
<span className="meta">
{TRIM_LABEL[trim]} · {idx + 1} of {chapters.length}
{TRIM_LABEL[book.settings.trim]} · {idx + 1} of {chapters.length}
</span>
</div>
<div className="page">
+16 -3
View File
@@ -28,12 +28,14 @@ function Field({ label, children }: { label: string; children: ReactNode }) {
);
}
export function Settings({ onClose }: { onClose: () => void }) {
const metadata = useBook((s) => s.book.metadata);
const settings = useBook((s) => s.book.settings);
export function Settings({ onClose, onSave }: { onClose: () => void; onSave: () => void }) {
const book = useBook((s) => s.book);
const setMetadata = useBook((s) => s.setMetadata);
const setSettings = useBook((s) => s.setSettings);
if (!book) return null;
const { metadata, settings } = book;
return (
<div className="overlay" onClick={onClose}>
<div className="panel" onClick={(e) => e.stopPropagation()}>
@@ -81,6 +83,17 @@ export function Settings({ onClose }: { onClose: () => void }) {
Add bleed for full-page images (print)
</label>
</div>
<div className="panel-foot">
<button
className="btn-primary"
onClick={() => {
onSave();
onClose();
}}
>
Save
</button>
</div>
</div>
</div>
);
+5 -4
View File
@@ -2,17 +2,18 @@ import { useBook } from "../store/useBook";
import { Icon } from "./Icon";
export function Sidebar() {
const chapters = useBook((s) => s.book.chapters);
const chapters = useBook((s) => s.book?.chapters ?? []);
const activeChapterId = useBook((s) => s.activeChapterId);
const setActiveChapter = useBook((s) => s.setActiveChapter);
const addChapter = useBook((s) => s.addChapter);
const closeBook = useBook((s) => s.closeBook);
return (
<aside className="sidebar">
<div className="brand">
<button className="brand" onClick={closeBook} title="Back to library">
<Icon d="M14 7l-5 5 5 5" size={15} />
<span className="mark">margin</span>
<span className="dot" />
</div>
</button>
<div className="nav-label">Chapters</div>
<ul className="chapters">
{chapters.map((chapter, i) => (