ai-chatbot/components/flow-board/xmind-image-export.tsx
134 23ced0b760 feat(flow-board): add rich notes, Gantt tasks and PNG export
Add native task metadata, working-day calendar settings, dependency scheduling and rich note editing. Support complete-sheet PNG export with resolution and transparency controls, preserve XMind extensions and update browser regressions.
2026-10-06 17:38:14 +08:00

95 lines
2.6 KiB
TypeScript

"use client";
import { Download, Loader2, X } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import type { ImageExportOptions } from "@/lib/flow-board/image-export";
export function XmindImageExport({
busy,
onExport,
onClose,
}: {
busy: boolean;
onExport: (
options: Pick<ImageExportOptions, "scale" | "transparent">
) => void;
onClose: () => void;
}) {
const dialog = useRef<HTMLDialogElement>(null);
const [scale, setScale] = useState<1 | 2 | 3>(2);
const [transparent, setTransparent] = useState(false);
useEffect(() => {
const node = dialog.current;
node?.showModal();
return () => node?.close();
}, []);
return (
<dialog
ref={dialog}
className="xmind-image-export"
aria-labelledby="image-export-title"
data-flow-board-shell-control="true"
onKeyDown={(event) => event.stopPropagation()}
onCancel={(event) => {
event.preventDefault();
if (!busy) onClose();
}}
>
<header>
<h2 id="image-export-title">导出图片</h2>
<button
type="button"
aria-label="关闭图片导出"
disabled={busy}
onClick={onClose}
>
<X size={18} />
</button>
</header>
<p>导出当前工作表的完整内容为 PNG 图片。</p>
<label className="xmind-image-export-field">
清晰度
<select
aria-label="图片清晰度"
value={scale}
disabled={busy}
onChange={(event) =>
setScale(Number(event.target.value) as 1 | 2 | 3)
}
>
<option value={1}>标准 · 1 倍</option>
<option value={2}>高清 · 2 倍</option>
<option value={3}>超清 · 3 倍</option>
</select>
</label>
<label className="xmind-image-export-check">
<input
type="checkbox"
checked={transparent}
disabled={busy}
onChange={(event) => setTransparent(event.target.checked)}
/>
透明背景
</label>
<footer>
<button type="button" disabled={busy} onClick={onClose}>
取消
</button>
<button
type="button"
className="xmind-primary-button"
disabled={busy}
onClick={() => onExport({ scale, transparent })}
>
{busy ? (
<Loader2 size={16} className="animate-spin" />
) : (
<Download size={16} />
)}
{busy ? "正在导出…" : "导出 PNG"}
</button>
</footer>
</dialog>
);
}