From 03e778a06f0b02d7295ace539ab6b26595f4a661 Mon Sep 17 00:00:00 2001 From: Zimeng Xiong Date: Mon, 24 Nov 2025 14:39:38 -0800 Subject: [PATCH] add export functionality via exportUtils --- frontend/src/components/DrawingCard.tsx | 13 ++++- frontend/src/pages/Editor.tsx | 22 ++++++- frontend/src/utils/exportUtils.ts | 78 +++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 frontend/src/utils/exportUtils.ts diff --git a/frontend/src/components/DrawingCard.tsx b/frontend/src/components/DrawingCard.tsx index a874341..b383d2d 100644 --- a/frontend/src/components/DrawingCard.tsx +++ b/frontend/src/components/DrawingCard.tsx @@ -1,11 +1,12 @@ import React, { useState, useEffect } from 'react'; import { createPortal } from 'react-dom'; -import { PenTool, Trash2, FolderInput, ArrowRight, Check, Clock, Copy } from 'lucide-react'; +import { PenTool, Trash2, FolderInput, ArrowRight, Check, Clock, Copy, Download } from 'lucide-react'; import type { Drawing, Collection } from '../types'; import { formatDistanceToNow } from 'date-fns'; import clsx from 'clsx'; import { exportToSvg } from "@excalidraw/excalidraw"; +import { exportDrawingToFile } from '../utils/exportUtils'; import * as api from '../api'; @@ -325,6 +326,16 @@ export const DrawingCard: React.FC = ({ Duplicate + +
+ +
+
; +} + +/** + * Export a drawing to a .excalidraw file and trigger download + */ +export const exportDrawingToFile = ( + drawing: Drawing, + filename?: string +): void => { + const exportData: ExportData = { + type: "excalidraw", + version: 2, + source: window.location.origin, + elements: drawing.elements || [], + appState: { + gridSize: drawing.appState?.gridSize ?? null, + viewBackgroundColor: drawing.appState?.viewBackgroundColor ?? "#ffffff", + }, + files: drawing.files || {}, + }; + + const blob = new Blob([JSON.stringify(exportData, null, 2)], { + type: "application/json", + }); + + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = filename || `${drawing.name}.excalidraw`; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); +}; + +/** + * Export drawing from Editor with current state + */ +export const exportFromEditor = ( + name: string, + elements: readonly any[], + appState: any, + files: Record +): void => { + const exportData: ExportData = { + type: "excalidraw", + version: 2, + source: window.location.origin, + elements: Array.from(elements), + appState: { + gridSize: appState?.gridSize ?? null, + viewBackgroundColor: appState?.viewBackgroundColor ?? "#ffffff", + }, + files: files || {}, + }; + + const blob = new Blob([JSON.stringify(exportData, null, 2)], { + type: "application/json", + }); + + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = `${name}.excalidraw`; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); +};