Compare commits

..

No commits in common. "170ef52154f7a923c39e2bf4ce96673e40dfc65c" and "d249d0f00d2b543a1b9bb8cab65a4faa3b1c83db" have entirely different histories.

3 changed files with 8 additions and 34 deletions

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "folio",
"version": "0.1.3",
"version": "0.1.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "folio",
"version": "0.1.3",
"version": "0.1.2",
"license": "MIT",
"dependencies": {
"@tiptap/core": "^2.27.2",

View file

@ -1,6 +1,6 @@
{
"name": "folio",
"version": "0.1.3",
"version": "0.1.2",
"description": "A simple, local, open-source desktop writing app.",
"productName": "Folio",
"author": "Folio Contributors",

View file

@ -502,36 +502,14 @@ function currentBookTitle(): string {
}
}
// GTK save dialogs started with a bare filename (no directory) re-synthesize
// the name from the last-browsed folder when the user navigates, producing
// names like "Some Folder/.odt". Always hand them an absolute path. The last
// export folder is remembered so exports reopen where the user left them.
function exportDefaultPath(filename: string): string {
const last = getSetting<string>("lastExportDir", "");
const dir =
last && fs.existsSync(last) && fs.statSync(last).isDirectory()
? last
: app.getPath("documents");
return path.join(dir, filename);
}
function rememberExportDir(filePath: string): void {
try {
setSetting("lastExportDir", path.dirname(filePath));
} catch {
// best-effort only
}
}
handleIpc("folio:exportMarkdown", async () => {
const bp = requireBook();
const { canceled, filePath } = await showSaveDialog({
title: "Export combined Markdown",
defaultPath: exportDefaultPath(`${currentBookTitle()}.md`),
defaultPath: `${currentBookTitle()}.md`,
filters: [{ name: "Markdown", extensions: ["md"] }],
});
if (canceled || !filePath) return { canceled: true } as const;
rememberExportDir(filePath);
fs.writeFileSync(filePath, combineMarkdown(bp), "utf-8");
return { ok: true, filePath };
});
@ -540,11 +518,10 @@ handleIpc("folio:exportZip", async () => {
const bp = requireBook();
const { canceled, filePath } = await showSaveDialog({
title: "Export book bundle (ZIP)",
defaultPath: exportDefaultPath(`${currentBookTitle()}.zip`),
defaultPath: `${currentBookTitle()}.zip`,
filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
});
if (canceled || !filePath) return { canceled: true } as const;
rememberExportDir(filePath);
const buf = await buildZip(bp);
fs.writeFileSync(filePath, buf);
return { ok: true, filePath };
@ -572,12 +549,11 @@ requireBook();
} else {
const { canceled, filePath: chosen } = await showSaveDialog({
title: "Export as PDF",
defaultPath: exportDefaultPath(`${base}${suffix}.pdf`),
defaultPath: `${base}${suffix}.pdf`,
filters: [{ name: "PDF Document", extensions: ["pdf"] }],
});
if (canceled || !chosen) return { canceled: true } as const;
filePath = chosen.endsWith(".pdf") ? chosen : `${chosen}.pdf`;
rememberExportDir(filePath);
}
const win = getWindow();
if (!win) return { error: "No window is open." };
@ -614,7 +590,7 @@ async function exportOffice(format: "docx" | "odt", chapterIds?: string[] | null
} else {
const { canceled, filePath: chosen } = await showSaveDialog({
title: `Export${selected ? " Selected Chapters" : " Full Book"} as ${format.toUpperCase()}`,
defaultPath: exportDefaultPath(`${base}${suffix}.${ext}`),
defaultPath: `${base}${suffix}.${ext}`,
filters: [
{
name: format === "docx" ? "Word Document" : "OpenDocument Text",
@ -624,7 +600,6 @@ async function exportOffice(format: "docx" | "odt", chapterIds?: string[] | null
});
if (canceled || !chosen) return { canceled: true } as const;
filePath = chosen.endsWith(`.${ext}`) ? chosen : `${chosen}.${ext}`;
rememberExportDir(filePath);
}
const meta = loadBook(bp);
const chapters = selected
@ -656,11 +631,10 @@ handleIpc("folio:saveChapterAs", async (_e, id: string) => {
if (!entry) return { error: "Chapter not found" };
const { canceled, filePath } = await showSaveDialog({
title: "Save Chapter As",
defaultPath: exportDefaultPath(`${entry.title}.md`),
defaultPath: `${entry.title}.md`,
filters: [{ name: "Markdown", extensions: ["md"] }],
});
if (canceled || !filePath) return { canceled: true } as const;
rememberExportDir(filePath);
const content = getChapterContent(bp, id);
fs.writeFileSync(filePath, content, "utf-8");
return { ok: true, filePath };