diff --git a/src/main/index.ts b/src/main/index.ts index 3051a2f..3b7b272 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -335,27 +335,35 @@ handleIpc("folio:getChapterContent", (_e, id: string) => getChapterContent(requireBook(), id) ); -handleIpc("folio:createChapter", (_e, title: string) => { - const entry = createChapter(requireBook(), title); +handleIpc("folio:createChapter", async (_e, title: string) => { + const bp = requireBook(); + const entry = createChapter(bp, title); notifyChange(); + void autoExportDocx(bp); return { id: entry.id, title: entry.title, file: entry.file }; }); -handleIpc("folio:renameChapter", (_e, id: string, title: string) => { - renameChapter(requireBook(), id, title); +handleIpc("folio:renameChapter", async (_e, id: string, title: string) => { + const bp = requireBook(); + renameChapter(bp, id, title); notifyChange(); + void autoExportDocx(bp); return { ok: true }; }); -handleIpc("folio:deleteChapter", (_e, id: string) => { - deleteChapter(requireBook(), id); +handleIpc("folio:deleteChapter", async (_e, id: string) => { + const bp = requireBook(); + deleteChapter(bp, id); notifyChange(); + void autoExportDocx(bp); return { ok: true }; }); -handleIpc("folio:restoreChapter", (_e, snap: unknown) => { - restoreChapter(requireBook(), snap as never); +handleIpc("folio:restoreChapter", async (_e, snap: unknown) => { + const bp = requireBook(); + restoreChapter(bp, snap as never); notifyChange(); + void autoExportDocx(bp); return { ok: true }; }); @@ -401,21 +409,27 @@ function restoreBookFromTrash(p: string): { ok?: boolean; error?: string } { handleIpc("folio:restoreBook", (_e, p: string) => restoreBookFromTrash(p)); -handleIpc("folio:duplicateChapter", (_e, id: string, title?: string) => { - const entry = duplicateChapter(requireBook(), id, title); +handleIpc("folio:duplicateChapter", async (_e, id: string, title?: string) => { + const bp = requireBook(); + const entry = duplicateChapter(bp, id, title); notifyChange(); + void autoExportDocx(bp); return { id: entry.id, title: entry.title }; }); -handleIpc("folio:setChapterColor", (_e, id: string, color: string | null) => { - setChapterColor(requireBook(), id, color); +handleIpc("folio:setChapterColor", async (_e, id: string, color: string | null) => { + const bp = requireBook(); + setChapterColor(bp, id, color); notifyChange(); + void autoExportDocx(bp); return { ok: true }; }); -handleIpc("folio:reorderChapters", (_e, newOrder: string[]) => { - reorderChapters(requireBook(), newOrder); +handleIpc("folio:reorderChapters", async (_e, newOrder: string[]) => { + const bp = requireBook(); + reorderChapters(bp, newOrder); notifyChange(); + void autoExportDocx(bp); return { ok: true }; }); @@ -545,8 +559,10 @@ async function exportOffice(format: "docx" | "odt", chapterIds?: string[] | null handleIpc("folio:exportDocx", (_e, chapterIds) => exportOffice("docx", chapterIds)); handleIpc("folio:exportOdt", (_e, chapterIds) => exportOffice("odt", chapterIds)); -handleIpc("folio:saveChapter", (_e, id: string, content: string) => { - setChapterContent(requireBook(), id, content); +handleIpc("folio:saveChapter", async (_e, id: string, content: string) => { + const bp = requireBook(); + setChapterContent(bp, id, content); + void autoExportDocx(bp); return { ok: true }; }); @@ -583,8 +599,42 @@ handleIpc("folio:loadChapterDoc", (_e, id: string) => // Persist a native document from the editor. Autosave writes directly to the // native JSON model (no Markdown round-trip). -handleIpc("folio:saveChapterDoc", (_e, id: string, doc: unknown) => { - saveChapterDoc(requireBook(), id, doc as never); +// Added: auto-export DOCX by default so every save also refreshes the +// book's .docx in the book folder (and a per-chapter docx). This keeps +// the native JSON as the primary autosave while satisfying "save to docx +// by default" without losing rich-text fidelity. +async function autoExportDocx(bookPath: string): Promise { + try { + const meta = loadBook(bookPath); + const full = await buildDocx(bookPath); + const outFull = path.join(bookPath, `${meta.title}.docx`); + fs.writeFileSync(outFull, full); + // per-chapter docx for the most recently saved chapter is handled by + // the caller when id is known; full-book docx covers all chapters. + } catch (e) { + console.error("[folio] auto docx export failed:", (e as Error).message); + } +} + +handleIpc("folio:saveChapterDoc", async (_e, id: string, doc: unknown) => { + const bp = requireBook(); + saveChapterDoc(bp, id, doc as never); + // fire-and-forget full-book DOCX update (also per-chapter for quick access) + try { + const meta = loadBook(bp); + const entry = meta.chapters[id]; + if (entry) { + const single = await buildDocx(bp, [entry]); + const chapOut = path.join( + bp, + `${entry.title.replace(/[\/\\:*?"<>|]/g, "_")}.docx` + ); + fs.writeFileSync(chapOut, single); + } + } catch (e) { + console.error("[folio] per-chapter docx failed:", (e as Error).message); + } + void autoExportDocx(bp); return { ok: true }; });