import { Copy, Download, FileCode, FileText, Share2, } from "lucide-react"; import React, { useState, useRef, useEffect } from "react"; import { useI18n } from "../../application/i18n/I18nProvider"; import { buildVaultNoteMarkdownExportFiles, sanitizeNoteExportFileNamePart, type VaultNote, } from "../../domain/notes"; import { copyToClipboard } from "../keychain/utils"; import { toast } from "../ui/toast"; import { buildTextFilesZipBlob } from "../../lib/textZip"; export interface NoteExportMenuProps { note: VaultNote | null; allNotes: VaultNote[]; className?: string; } export const NoteExportMenu: React.FC = ({ note, allNotes, className = "", }) => { const { t } = useI18n(); const [open, setOpen] = useState(false); const menuRef = useRef(null); useEffect(() => { if (!open) return; const handleClickOutside = (e: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { setOpen(false); } }; window.addEventListener("mousedown", handleClickOutside); return () => window.removeEventListener("mousedown", handleClickOutside); }, [open]); const handleExportSingleMarkdown = () => { if (!note) return; const fileName = `${sanitizeNoteExportFileNamePart(note.title, "note")}.md`; const blob = new Blob([note.content], { type: "text/markdown;charset=utf-8" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = fileName; a.click(); URL.revokeObjectURL(url); toast.success(t("notes.exportSuccess") || "已导出 Markdown 文件"); setOpen(false); }; const handleExportSingleHtml = () => { if (!note) return; const title = note.title || "Untitled Note"; const escapedTitle = title.replace(//g, ">"); const htmlContent = ` ${escapedTitle}

${escapedTitle}

${note.content.replace(//g, ">")}
`; const fileName = `${sanitizeNoteExportFileNamePart(note.title, "note")}.html`; const blob = new Blob([htmlContent], { type: "text/html;charset=utf-8" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = fileName; a.click(); URL.revokeObjectURL(url); toast.success(t("notes.exportSuccess") || "已导出 HTML 文件"); setOpen(false); }; const handleCopyMarkdown = async () => { if (!note) return; const ok = await copyToClipboard(note.content); if (ok) { toast.success(t("common.copied") || "已复制到剪贴板"); } setOpen(false); }; const handleExportAllZip = () => { if (!allNotes.length) return; const files = buildVaultNoteMarkdownExportFiles(allNotes, { type: "all" }); const zipBlob = buildTextFilesZipBlob(files); const url = URL.createObjectURL(zipBlob); const a = document.createElement("a"); a.href = url; a.download = `netcatty-notes-backup-${new Date().toISOString().slice(0, 10)}.zip`; a.click(); URL.revokeObjectURL(url); toast.success(t("notes.exportAllSuccess") || "已导出全部笔记备份 ZIP"); setOpen(false); }; return (
{open && (
{note && ( <>
当前笔记
)}
全部笔记
)}
); };