Compare commits
2 commits
d249d0f00d
...
170ef52154
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
170ef52154 | ||
|
|
4af49f8f3c |
3 changed files with 34 additions and 8 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "folio",
|
"name": "folio",
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "folio",
|
"name": "folio",
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tiptap/core": "^2.27.2",
|
"@tiptap/core": "^2.27.2",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "folio",
|
"name": "folio",
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"description": "A simple, local, open-source desktop writing app.",
|
"description": "A simple, local, open-source desktop writing app.",
|
||||||
"productName": "Folio",
|
"productName": "Folio",
|
||||||
"author": "Folio Contributors",
|
"author": "Folio Contributors",
|
||||||
|
|
|
||||||
|
|
@ -502,14 +502,36 @@ 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 () => {
|
handleIpc("folio:exportMarkdown", async () => {
|
||||||
const bp = requireBook();
|
const bp = requireBook();
|
||||||
const { canceled, filePath } = await showSaveDialog({
|
const { canceled, filePath } = await showSaveDialog({
|
||||||
title: "Export combined Markdown",
|
title: "Export combined Markdown",
|
||||||
defaultPath: `${currentBookTitle()}.md`,
|
defaultPath: exportDefaultPath(`${currentBookTitle()}.md`),
|
||||||
filters: [{ name: "Markdown", extensions: ["md"] }],
|
filters: [{ name: "Markdown", extensions: ["md"] }],
|
||||||
});
|
});
|
||||||
if (canceled || !filePath) return { canceled: true } as const;
|
if (canceled || !filePath) return { canceled: true } as const;
|
||||||
|
rememberExportDir(filePath);
|
||||||
fs.writeFileSync(filePath, combineMarkdown(bp), "utf-8");
|
fs.writeFileSync(filePath, combineMarkdown(bp), "utf-8");
|
||||||
return { ok: true, filePath };
|
return { ok: true, filePath };
|
||||||
});
|
});
|
||||||
|
|
@ -518,10 +540,11 @@ handleIpc("folio:exportZip", async () => {
|
||||||
const bp = requireBook();
|
const bp = requireBook();
|
||||||
const { canceled, filePath } = await showSaveDialog({
|
const { canceled, filePath } = await showSaveDialog({
|
||||||
title: "Export book bundle (ZIP)",
|
title: "Export book bundle (ZIP)",
|
||||||
defaultPath: `${currentBookTitle()}.zip`,
|
defaultPath: exportDefaultPath(`${currentBookTitle()}.zip`),
|
||||||
filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
|
filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
|
||||||
});
|
});
|
||||||
if (canceled || !filePath) return { canceled: true } as const;
|
if (canceled || !filePath) return { canceled: true } as const;
|
||||||
|
rememberExportDir(filePath);
|
||||||
const buf = await buildZip(bp);
|
const buf = await buildZip(bp);
|
||||||
fs.writeFileSync(filePath, buf);
|
fs.writeFileSync(filePath, buf);
|
||||||
return { ok: true, filePath };
|
return { ok: true, filePath };
|
||||||
|
|
@ -549,11 +572,12 @@ requireBook();
|
||||||
} else {
|
} else {
|
||||||
const { canceled, filePath: chosen } = await showSaveDialog({
|
const { canceled, filePath: chosen } = await showSaveDialog({
|
||||||
title: "Export as PDF",
|
title: "Export as PDF",
|
||||||
defaultPath: `${base}${suffix}.pdf`,
|
defaultPath: exportDefaultPath(`${base}${suffix}.pdf`),
|
||||||
filters: [{ name: "PDF Document", extensions: ["pdf"] }],
|
filters: [{ name: "PDF Document", extensions: ["pdf"] }],
|
||||||
});
|
});
|
||||||
if (canceled || !chosen) return { canceled: true } as const;
|
if (canceled || !chosen) return { canceled: true } as const;
|
||||||
filePath = chosen.endsWith(".pdf") ? chosen : `${chosen}.pdf`;
|
filePath = chosen.endsWith(".pdf") ? chosen : `${chosen}.pdf`;
|
||||||
|
rememberExportDir(filePath);
|
||||||
}
|
}
|
||||||
const win = getWindow();
|
const win = getWindow();
|
||||||
if (!win) return { error: "No window is open." };
|
if (!win) return { error: "No window is open." };
|
||||||
|
|
@ -590,7 +614,7 @@ async function exportOffice(format: "docx" | "odt", chapterIds?: string[] | null
|
||||||
} else {
|
} else {
|
||||||
const { canceled, filePath: chosen } = await showSaveDialog({
|
const { canceled, filePath: chosen } = await showSaveDialog({
|
||||||
title: `Export${selected ? " Selected Chapters" : " Full Book"} as ${format.toUpperCase()}`,
|
title: `Export${selected ? " Selected Chapters" : " Full Book"} as ${format.toUpperCase()}`,
|
||||||
defaultPath: `${base}${suffix}.${ext}`,
|
defaultPath: exportDefaultPath(`${base}${suffix}.${ext}`),
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
name: format === "docx" ? "Word Document" : "OpenDocument Text",
|
name: format === "docx" ? "Word Document" : "OpenDocument Text",
|
||||||
|
|
@ -600,6 +624,7 @@ async function exportOffice(format: "docx" | "odt", chapterIds?: string[] | null
|
||||||
});
|
});
|
||||||
if (canceled || !chosen) return { canceled: true } as const;
|
if (canceled || !chosen) return { canceled: true } as const;
|
||||||
filePath = chosen.endsWith(`.${ext}`) ? chosen : `${chosen}.${ext}`;
|
filePath = chosen.endsWith(`.${ext}`) ? chosen : `${chosen}.${ext}`;
|
||||||
|
rememberExportDir(filePath);
|
||||||
}
|
}
|
||||||
const meta = loadBook(bp);
|
const meta = loadBook(bp);
|
||||||
const chapters = selected
|
const chapters = selected
|
||||||
|
|
@ -631,10 +656,11 @@ handleIpc("folio:saveChapterAs", async (_e, id: string) => {
|
||||||
if (!entry) return { error: "Chapter not found" };
|
if (!entry) return { error: "Chapter not found" };
|
||||||
const { canceled, filePath } = await showSaveDialog({
|
const { canceled, filePath } = await showSaveDialog({
|
||||||
title: "Save Chapter As",
|
title: "Save Chapter As",
|
||||||
defaultPath: `${entry.title}.md`,
|
defaultPath: exportDefaultPath(`${entry.title}.md`),
|
||||||
filters: [{ name: "Markdown", extensions: ["md"] }],
|
filters: [{ name: "Markdown", extensions: ["md"] }],
|
||||||
});
|
});
|
||||||
if (canceled || !filePath) return { canceled: true } as const;
|
if (canceled || !filePath) return { canceled: true } as const;
|
||||||
|
rememberExportDir(filePath);
|
||||||
const content = getChapterContent(bp, id);
|
const content = getChapterContent(bp, id);
|
||||||
fs.writeFileSync(filePath, content, "utf-8");
|
fs.writeFileSync(filePath, content, "utf-8");
|
||||||
return { ok: true, filePath };
|
return { ok: true, filePath };
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue