123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- import React from "react";
- import { Card } from "../../packages/excalidraw/components/Card";
- import { ToolButton } from "../../packages/excalidraw/components/ToolButton";
- import { serializeAsJSON } from "../../packages/excalidraw/data/json";
- import { loadFirebaseStorage, saveFilesToFirebase } from "../data/firebase";
- import {
- FileId,
- NonDeletedExcalidrawElement,
- } from "../../packages/excalidraw/element/types";
- import {
- AppState,
- BinaryFileData,
- BinaryFiles,
- } from "../../packages/excalidraw/types";
- import { nanoid } from "nanoid";
- import { useI18n } from "../../packages/excalidraw/i18n";
- import {
- encryptData,
- generateEncryptionKey,
- } from "../../packages/excalidraw/data/encryption";
- import { isInitializedImageElement } from "../../packages/excalidraw/element/typeChecks";
- import { FILE_UPLOAD_MAX_BYTES } from "../app_constants";
- import { encodeFilesForUpload } from "../data/FileManager";
- import { MIME_TYPES } from "../../packages/excalidraw/constants";
- import { trackEvent } from "../../packages/excalidraw/analytics";
- import { getFrame } from "../../packages/excalidraw/utils";
- import { ExcalidrawLogo } from "../../packages/excalidraw/components/ExcalidrawLogo";
- export const exportToExcalidrawPlus = async (
- elements: readonly NonDeletedExcalidrawElement[],
- appState: Partial<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<FileId, BinaryFileData>();
- 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(
- `${
- import.meta.env.VITE_APP_PLUS_APP
- }/import?excalidraw=${id},${encryptionKey}`,
- );
- };
- export const ExportToExcalidrawPlus: React.FC<{
- elements: readonly NonDeletedExcalidrawElement[];
- appState: Partial<AppState>;
- files: BinaryFiles;
- onError: (error: Error) => void;
- onSuccess: () => void;
- }> = ({ elements, appState, files, onError, onSuccess }) => {
- const { t } = useI18n();
- return (
- <Card color="primary">
- <div className="Card-icon">
- <ExcalidrawLogo
- style={{
- [`--color-logo-icon` as any]: "#fff",
- width: "2.8rem",
- height: "2.8rem",
- }}
- />
- </div>
- <h2>Excalidraw+</h2>
- <div className="Card-details">
- {t("exportDialog.excalidrawplus_description")}
- </div>
- <ToolButton
- className="Card-button"
- type="button"
- title={t("exportDialog.excalidrawplus_button")}
- aria-label={t("exportDialog.excalidrawplus_button")}
- showAriaLabel={true}
- onClick={async () => {
- try {
- trackEvent("export", "eplus", `ui (${getFrame()})`);
- await exportToExcalidrawPlus(elements, appState, files);
- onSuccess();
- } catch (error: any) {
- console.error(error);
- if (error.name !== "AbortError") {
- onError(new Error(t("exportDialog.excalidrawplus_exportError")));
- }
- }
- }}
- />
- </Card>
- );
- };
|