Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ import {
import { formatTable, toggleTaskCheckboxOnLine } from "./lib/cm-table-format";
import { collapseBlankLines } from "./lib/collapse-blanks";
import { sliceEmbed, splitEmbedTarget } from "./lib/embed-slice";
import { exportHtml, exportPdfViaPrint } from "./lib/export";
import { exportPdfViaPrint } from "./lib/export";
import { installFocusTypewriter } from "./lib/focus-typewriter";
import { wikilinkAtCursor } from "./lib/follow-wikilink";
import {
Expand Down Expand Up @@ -131,6 +131,7 @@ import {
refreshGitHubVault,
openNewWindow,
openVault,
pickHtmlSavePath,
pickSavePath,
pickVault,
pushRecentFileNative,
Expand Down Expand Up @@ -1215,19 +1216,38 @@ export function App() {
}, []);

async function handleExportHtml() {
if (!tab) return;
const baseName = (tab.name || "Untitled").replace(/\.[^.]+$/, "");
// Read the live active tab from the store, not a captured render closure:
// the menu listener is registered once, so a closed-over `tab` would always
// be the first (welcome) document.
const state = useAppStore.getState();
const t = state.activeTabId
? state.tabs.find((x) => x.id === state.activeTabId)
: null;
if (!t) return;
const baseName = (t.name || "Untitled").replace(/\.[^.]+$/, "");
try {
await exportHtml(tab.content, baseName, exportTheme);
// Let the user pick where to save (instead of a silent Downloads dump).
const raw = await pickHtmlSavePath(`${baseName}.html`);
if (!raw) return; // cancelled
const target = /\.html?$/i.test(raw) ? raw : `${raw}.html`;
const html = await renderHtml(t.content, baseName, exportTheme);
await writeFile(target, html, null);
showToast(tr("toast.exportedHtml", target.split("/").pop() || target));
} catch (e) {
console.error("exportHtml failed", e);
setActiveStatus("error", String(e));
}
}
async function handleExportPdf() {
if (!tab) return;
const title = tab.name || "Untitled";
// Same stale-closure fix as handleExportHtml — read the live active tab.
const state = useAppStore.getState();
const t = state.activeTabId
? state.tabs.find((x) => x.id === state.activeTabId)
: null;
if (!t) return;
const title = t.name || "Untitled";
try {
await exportPdfViaPrint(tab.content, title, exportTheme);
await exportPdfViaPrint(t.content, title, exportTheme);
} catch (e) {
console.error("exportPdf failed", e);
}
Expand Down
22 changes: 0 additions & 22 deletions src/lib/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,3 @@ export async function exportPdfViaPrint(
win.focus();
win.print();
}

/** Trigger a download of a string as `filename` with given mime. */
function downloadString(text: string, filename: string, mime: string) {
const blob = new Blob([text], { type: mime });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
setTimeout(() => URL.revokeObjectURL(url), 1000);
}

export async function exportHtml(
content: string,
baseName: string,
theme: ExportTheme = "github",
) {
const html = await renderHtml(content, baseName, theme);
downloadString(html, `${baseName}.html`, "text/html");
}
1 change: 1 addition & 0 deletions src/lib/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export const en = {
"toast.githubUpdated": "GitHub vault updated ({0})",
"toast.githubUpToDate": "Already up to date",
"toast.githubPullFailed": "Couldn't pull from GitHub",
"toast.exportedHtml": "Exported {0}",
"github.confirmPullDirty":
"{0} file(s) have local changes since the last sync. Pulling from GitHub will overwrite them. Continue?",
"toast.renameNoFile": "No file to rename",
Expand Down
1 change: 1 addition & 0 deletions src/lib/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export const zh: Strings = {
"toast.githubUpdated": "GitHub 仓库已更新({0})",
"toast.githubUpToDate": "已是最新",
"toast.githubPullFailed": "无法从 GitHub 拉取",
"toast.exportedHtml": "已导出 {0}",
"github.confirmPullDirty":
"有 {0} 个文件在上次同步后被本地修改过。从 GitHub 拉取会覆盖这些改动。是否继续?",
"toast.renameNoFile": "没有可重命名的文件",
Expand Down
12 changes: 12 additions & 0 deletions src/lib/tauri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ export async function pickSavePath(defaultName: string): Promise<string | null>
return path ?? null;
}

/** Save dialog for an exported HTML file (filters to .html). Authorizes the
* chosen path for writing, like pickSavePath. */
export async function pickHtmlSavePath(defaultName: string): Promise<string | null> {
const path = await saveDialog({
title: "Export as HTML",
defaultPath: defaultName,
filters: [{ name: "HTML", extensions: ["html", "htm"] }],
});
if (path) await authorizePaths([path]);
return path ?? null;
}

export async function openFileDialog(): Promise<LoadedFile | null> {
return await invoke<LoadedFile | null>("open_file");
}
Expand Down
Loading