feat: add PNG/SVG export and expandable card property tips

Toolbar exports PNG (fit+raster) and SVG; card click expands full fields, hover shows property tooltips, double-click opens the editor.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-17 10:43:33 +08:00
parent 23ff27122f
commit 4c9bd5b86f
22 changed files with 978 additions and 315 deletions

View file

@ -390,6 +390,35 @@ export function startMindMapServer(
}
});
app.get("/api/canvases/:id/export.svg", async (c) => {
try {
const id = c.req.param("id");
const result = (await runTool(
"mindmap_export",
{ format: "svg", canvasId: id },
{ store, broadcast, defaultCanvasId: id },
)) as {
ok?: boolean;
svg?: string;
title?: string;
};
if (!result?.ok || typeof result.svg !== "string") {
return c.json({ ok: false, error: "export_failed" }, 400);
}
const safe =
String(result.title ?? "mindmap").replace(/[\\/:*?"<>|]+/g, "_") ||
"mindmap";
return new Response(result.svg, {
headers: {
"Content-Type": "image/svg+xml; charset=utf-8",
"Content-Disposition": `attachment; filename="${safe}.svg"`,
},
});
} catch {
return c.json({ ok: false, error: "not_found" }, 404);
}
});
app.post("/api/tools/:name", async (c) => {
const name = c.req.param("name");
const args = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;

View file

@ -243,7 +243,7 @@ function escapeXml(s: string): string {
.replace(/"/g, "&quot;");
}
function exportSvg(
export function exportSvg(
nodes: MindNode[],
edges: MindEdge[],
positions: Record<string, { x: number; y: number }>,
@ -1108,24 +1108,37 @@ export async function runTool(
snap.canvas.title,
anchorId,
);
if (format === "png") {
// Server has no font/raster stack; return SVG payload plus png mime hint.
// Web UI toolbar「PNG」rasterizes the live canvas (CJK-accurate).
return {
ok: true,
format: "svg",
requestedFormat: "png",
title: snap.canvas.title,
mimeType: "image/svg+xml",
svg,
nodeCount: publicNodes.length,
edgeCount: publicEdges.length,
hint:
"PNG raster needs the web UI toolbar button (system fonts). This tool returns SVG which pastes into docs/PPT; save as .svg or convert locally.",
};
}
return {
ok: true,
format: format === "png" ? "svg" : "svg",
format: "svg",
title: snap.canvas.title,
mimeType: "image/svg+xml",
svg,
nodeCount: publicNodes.length,
edgeCount: publicEdges.length,
hint:
format === "png"
? "Agent export returns SVG (vector). For raster PNG use the web UI「导出PNG」; SVG pastes into docs/PPT as well."
: "SVG can be saved as .svg or opened in browser / Office.",
hint: "SVG can be saved as .svg or opened in browser / Office.",
};
}
return {
ok: false,
error: "invalid_op",
message: 'format must be "json" | "md" | "svg" (png → svg for agents; UI has raster PNG)',
message: 'format must be "json" | "md" | "svg" | "png"',
};
}