diff --git a/src/App.tsx b/src/App.tsx index c693b3c..74437b1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import type { Editor as TiptapEditor } from "@tiptap/react"; import { Sidebar } from "./components/Sidebar"; import { Dock } from "./components/Dock"; @@ -6,6 +6,7 @@ import { Icon } from "./components/Icon"; import { Editor } from "./editor/Editor"; import { FloatingToolbar } from "./editor/FloatingToolbar"; import { useBook } from "./store/useBook"; +import { chooseSavePath, openBook, writeBook } from "./project"; function App() { const [dock, setDock] = useState(true); @@ -14,20 +15,59 @@ function App() { 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]); + return (