import React from "react"; import { Card } from "../../components/Card"; import { ToolButton } from "../../components/ToolButton"; import { serializeAsJSON } from "../../data/json"; import { loadFirebaseStorage, saveFilesToFirebase } from "../data/firebase"; import { FileId, NonDeletedExcalidrawElement } from "../../element/types"; import { AppState, BinaryFileData, BinaryFiles } from "../../types"; import { nanoid } from "nanoid"; import { t } from "../../i18n"; import { excalidrawPlusIcon } from "./icons"; import { encryptData, generateEncryptionKey } from "../../data/encryption"; import { isInitializedImageElement } from "../../element/typeChecks"; import { FILE_UPLOAD_MAX_BYTES } from "../app_constants"; import { encodeFilesForUpload } from "../data/FileManager"; import { MIME_TYPES } from "../../constants"; const exportToExcalidrawPlus = async ( elements: readonly NonDeletedExcalidrawElement[], appState: AppState, files: BinaryFiles, ) => { const firebase = await loadFirebaseStorage(); const id = `${nanoid(12)}`; const encryptionKey = (await generateEncryptionKey())!; const encryptedData = await encryptData( encryptionKey, serializeAsJSON(elements, appState, files, "database"), ); const blob = new Blob( [encryptedData.iv, new Uint8Array(encryptedData.encryptedBuffer)], { type: MIME_TYPES.binary, }, ); await firebase .storage() .ref(`/migrations/scenes/${id}`) .put(blob, { customMetadata: { data: JSON.stringify({ version: 2, name: appState.name }), created: Date.now().toString(), }, }); const filesMap = new Map(); for (const element of elements) { if (isInitializedImageElement(element) && files[element.fileId]) { filesMap.set(element.fileId, files[element.fileId]); } } if (filesMap.size) { const filesToUpload = await encodeFilesForUpload({ files: filesMap, encryptionKey, maxBytes: FILE_UPLOAD_MAX_BYTES, }); await saveFilesToFirebase({ prefix: `/migrations/files/scenes/${id}`, files: filesToUpload, }); } window.open( `https://plus.excalidraw.com/import?excalidraw=${id},${encryptionKey}`, ); }; export const ExportToExcalidrawPlus: React.FC<{ elements: readonly NonDeletedExcalidrawElement[]; appState: AppState; files: BinaryFiles; onError: (error: Error) => void; }> = ({ elements, appState, files, onError }) => { return (
{excalidrawPlusIcon}

Excalidraw+

{t("exportDialog.excalidrawplus_description")}
{ try { await exportToExcalidrawPlus(elements, appState, files); } catch (error: any) { console.error(error); if (error.name !== "AbortError") { onError(new Error(t("exportDialog.excalidrawplus_exportError"))); } } }} />
); };