import { loginIcon, ExcalLogo, eyeIcon, pngIcon, } from "@excalidraw/excalidraw/components/icons"; import { MainMenu } from "@excalidraw/excalidraw/index"; import React from "react"; import { getVersion, isDevEnv } from "@excalidraw/common"; import { fileOpen, fileSave } from "@excalidraw/excalidraw/data/filesystem"; import superjson from "superjson"; import { getDefaultAppState } from "@excalidraw/excalidraw/appState"; import type { Theme } from "@excalidraw/element/types"; import type { AppState, ExcalidrawImperativeAPI, } from "@excalidraw/excalidraw/types"; import { LanguageList } from "../app-language/LanguageList"; import { isExcalidrawPlusSignedUser } from "../app_constants"; import { saveDebugState } from "./DebugCanvas"; export const AppMainMenu: React.FC<{ onCollabDialogOpen: () => any; isCollaborating: boolean; isCollabEnabled: boolean; theme: Theme | "system"; setTheme: (theme: Theme | "system") => void; refresh: () => void; excalidrawAPI: ExcalidrawImperativeAPI | null; }> = React.memo((props) => { return ( {props.isCollabEnabled && ( props.onCollabDialogOpen()} /> )} Excalidraw+ {isExcalidrawPlusSignedUser ? "Sign in" : "Sign up"} {isDevEnv() && ( <> { if (window.visualDebug) { delete window.visualDebug; saveDebugState({ enabled: false }); } else { window.visualDebug = { data: [] }; saveDebugState({ enabled: true }); } props?.refresh(); }} > Visual Debug {props.excalidrawAPI && ( <> { const blob = await fileOpen({ description: "Excalidraw test case recording", extensions: ["json"], }); const text = await blob.text(); const recording = superjson.parse(text); window.setRecordedDataRef(null); const start = recording.shift(); window.resizeTo( start.dimensions.innerWidth, start.dimensions.innerHeight, ); if ( Math.abs(start.dimensions.innerWidth - window.innerWidth) > 1 || Math.abs( start.dimensions.innerHeight - window.innerHeight, ) > 1 ) { console.error("Window dimensions do not match"); return; } props.excalidrawAPI!.resetScene(); props.excalidrawAPI!.updateScene({ elements: superjson.parse(start.scene), appState: { ...getDefaultAppState(), ...superjson.parse(start.state), }, }); let lastTime = start.time; for (const item of recording) { if (item.type === "event") { const { time, type, name, ...rest } = item; const delay = time - lastTime; lastTime = time; await new Promise((resolve) => setTimeout(resolve, delay), ); console.log(type, name, rest); window.runReplay(name, rest); } } }} > Run Recording... { window.setRecordedDataRef([ { time: new Date().getTime(), type: "start", excalidrawVersion: getVersion(), dimensions: { innerWidth: window.innerWidth, innerHeight: window.innerHeight, }, chromeVersion: window.navigator.userAgent .split(" ") .find((v) => v.startsWith("Chrome/")) ?.substring(7), state: superjson.stringify( props.excalidrawAPI!.getAppState(), ), scene: superjson.stringify( props.excalidrawAPI!.getSceneElementsIncludingDeleted(), ), }, ]); }} > Start Recording { const blob = new Blob( [superjson.stringify(window.getRecordedDataRef())], { type: "text/json", }, ); try { await fileSave(blob, { name: `testcase-${new Date().getTime()}${Math.floor( Math.random() * 10000, )}`, extension: "json", description: "Excalidraw test case recording", }); } catch (error) {} }} > Save Recording... )} )} ); });