import { useCallback, useEffect, useState } from "react"; import type { Editor as TiptapEditor } from "@tiptap/react"; import { Sidebar } from "./components/Sidebar"; import { Dock } from "./components/Dock"; import { Icon } from "./components/Icon"; import { Settings } from "./components/Settings"; import { Editor } from "./editor/Editor"; import { FloatingToolbar } from "./editor/FloatingToolbar"; import { useBook } from "./store/useBook"; import type { Book } from "./model/book"; import { chooseSavePath, openBook, writeBook } from "./project"; import { exportEpub, exportPdf } from "./export/exporters"; function App() { const [dock, setDock] = useState(true); const [editor, setEditor] = useState(null); const [settingsOpen, setSettingsOpen] = useState(false); const [exportOpen, setExportOpen] = useState(false); const title = useBook((s) => s.book.metadata.title); const author = useBook((s) => s.book.metadata.author); const chapters = useBook((s) => s.book.chapters); const activeChapterId = useBook((s) => s.activeChapterId); const dirty = useBook((s) => s.dirty); const setChapterContent = useBook((s) => s.setChapterContent); const setChapterTitle = useBook((s) => s.setChapterTitle); const replaceBook = useBook((s) => s.replaceBook); const markSaved = useBook((s) => s.markSaved); const idx = chapters.findIndex((c) => c.id === activeChapterId); const chapter = chapters[idx]; const handleSave = useCallback(async () => { const { book, path } = useBook.getState(); const target = path ?? (await chooseSavePath(book)); if (!target) return; await writeBook(book, target); markSaved(target); }, [markSaved]); const handleOpen = useCallback(async () => { const result = await openBook(); if (result) replaceBook(result.book, result.path); }, [replaceBook]); useEffect(() => { const onKey = (e: KeyboardEvent) => { const mod = e.metaKey || e.ctrlKey; if (mod && e.key.toLowerCase() === "s") { e.preventDefault(); handleSave(); } if (mod && e.key.toLowerCase() === "o") { e.preventDefault(); handleOpen(); } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [handleSave, handleOpen]); const runExport = async (fn: (book: Book) => Promise) => { setExportOpen(false); try { await fn(useBook.getState().book); } catch (e) { console.error(e); } }; return (
{exportOpen && ( <>
setExportOpen(false)} />
)}
Chapter {idx + 1}
setChapterTitle(chapter.id, e.target.value)} />
setChapterContent(chapter.id, content)} onReady={setEditor} />
{dock && }
{settingsOpen && setSettingsOpen(false)} />}
); } export default App;