import { getShortcutFromShortcutName } from "../../actions/shortcuts"; import { useI18n } from "../../i18n"; import { useExcalidrawSetAppState, useExcalidrawActionManager, useExcalidrawElements, useAppProps, } from "../App"; import { boltIcon, DeviceDesktopIcon, ExportIcon, ExportImageIcon, HelpIcon, LoadIcon, MoonIcon, save, SunIcon, TrashIcon, usersIcon, } from "../icons"; import { GithubIcon, DiscordIcon, XBrandIcon } from "../icons"; import DropdownMenuItem from "../dropdownMenu/DropdownMenuItem"; import DropdownMenuItemLink from "../dropdownMenu/DropdownMenuItemLink"; import { actionClearCanvas, actionLoadScene, actionSaveToActiveFile, actionShortcuts, actionToggleTheme, } from "../../actions"; import clsx from "clsx"; import { useSetAtom } from "jotai"; import { activeConfirmDialogAtom } from "../ActiveConfirmDialog"; import { jotaiScope } from "../../jotai"; import { useUIAppState } from "../../context/ui-appState"; import { openConfirmModal } from "../OverwriteConfirm/OverwriteConfirmState"; import Trans from "../Trans"; import DropdownMenuItemContentRadio from "../dropdownMenu/DropdownMenuItemContentRadio"; import { THEME } from "../../constants"; import type { Theme } from "../../element/types"; import { trackEvent } from "../../analytics"; import "./DefaultItems.scss"; export const LoadScene = () => { const { t } = useI18n(); const actionManager = useExcalidrawActionManager(); const elements = useExcalidrawElements(); if (!actionManager.isActionEnabled(actionLoadScene)) { return null; } const handleSelect = async () => { if ( !elements.length || (await openConfirmModal({ title: t("overwriteConfirm.modal.loadFromFile.title"), actionLabel: t("overwriteConfirm.modal.loadFromFile.button"), color: "warning", description: ( {text}} br={() =>
} /> ), })) ) { actionManager.executeAction(actionLoadScene); } }; return ( {t("buttons.load")} ); }; LoadScene.displayName = "LoadScene"; export const SaveToActiveFile = () => { const { t } = useI18n(); const actionManager = useExcalidrawActionManager(); if (!actionManager.isActionEnabled(actionSaveToActiveFile)) { return null; } return ( actionManager.executeAction(actionSaveToActiveFile)} icon={save} aria-label={`${t("buttons.save")}`} >{`${t("buttons.save")}`} ); }; SaveToActiveFile.displayName = "SaveToActiveFile"; export const SaveAsImage = () => { const setAppState = useExcalidrawSetAppState(); const { t } = useI18n(); return ( setAppState({ openDialog: { name: "imageExport" } })} shortcut={getShortcutFromShortcutName("imageExport")} aria-label={t("buttons.exportImage")} > {t("buttons.exportImage")} ); }; SaveAsImage.displayName = "SaveAsImage"; export const CommandPalette = (opts?: { className?: string }) => { const setAppState = useExcalidrawSetAppState(); const { t } = useI18n(); return ( { trackEvent("command_palette", "open", "menu"); setAppState({ openDialog: { name: "commandPalette" } }); }} shortcut={getShortcutFromShortcutName("commandPalette")} aria-label={t("commandPalette.title")} className={opts?.className} > {t("commandPalette.title")} ); }; CommandPalette.displayName = "CommandPalette"; export const Help = () => { const { t } = useI18n(); const actionManager = useExcalidrawActionManager(); return ( actionManager.executeAction(actionShortcuts)} shortcut="?" aria-label={t("helpDialog.title")} > {t("helpDialog.title")} ); }; Help.displayName = "Help"; export const ClearCanvas = () => { const { t } = useI18n(); const setActiveConfirmDialog = useSetAtom( activeConfirmDialogAtom, jotaiScope, ); const actionManager = useExcalidrawActionManager(); if (!actionManager.isActionEnabled(actionClearCanvas)) { return null; } return ( setActiveConfirmDialog("clearCanvas")} data-testid="clear-canvas-button" aria-label={t("buttons.clearReset")} > {t("buttons.clearReset")} ); }; ClearCanvas.displayName = "ClearCanvas"; export const ToggleTheme = ( props: | { allowSystemTheme: true; theme: Theme | "system"; onSelect: (theme: Theme | "system") => void; } | { allowSystemTheme?: false; onSelect?: (theme: Theme) => void; }, ) => { const { t } = useI18n(); const appState = useUIAppState(); const actionManager = useExcalidrawActionManager(); const shortcut = getShortcutFromShortcutName("toggleTheme"); if (!actionManager.isActionEnabled(actionToggleTheme)) { return null; } if (props?.allowSystemTheme) { return ( props.onSelect(value)} choices={[ { value: THEME.LIGHT, label: SunIcon, ariaLabel: `${t("buttons.lightMode")} - ${shortcut}`, }, { value: THEME.DARK, label: MoonIcon, ariaLabel: `${t("buttons.darkMode")} - ${shortcut}`, }, { value: "system", label: DeviceDesktopIcon, ariaLabel: t("buttons.systemMode"), }, ]} > {t("labels.theme")} ); } return ( { // do not close the menu when changing theme event.preventDefault(); if (props?.onSelect) { props.onSelect( appState.theme === THEME.DARK ? THEME.LIGHT : THEME.DARK, ); } else { return actionManager.executeAction(actionToggleTheme); } }} icon={appState.theme === THEME.DARK ? SunIcon : MoonIcon} data-testid="toggle-dark-mode" shortcut={shortcut} aria-label={ appState.theme === THEME.DARK ? t("buttons.lightMode") : t("buttons.darkMode") } > {appState.theme === THEME.DARK ? t("buttons.lightMode") : t("buttons.darkMode")} ); }; ToggleTheme.displayName = "ToggleTheme"; export const ChangeCanvasBackground = () => { const { t } = useI18n(); const appState = useUIAppState(); const actionManager = useExcalidrawActionManager(); const appProps = useAppProps(); if ( appState.viewModeEnabled || !appProps.UIOptions.canvasActions.changeViewBackgroundColor ) { return null; } return (
{t("labels.canvasBackground")}
{actionManager.renderAction("changeViewBackgroundColor")}
); }; ChangeCanvasBackground.displayName = "ChangeCanvasBackground"; export const Export = () => { const { t } = useI18n(); const setAppState = useExcalidrawSetAppState(); return ( { setAppState({ openDialog: { name: "jsonExport" } }); }} data-testid="json-export-button" aria-label={t("buttons.export")} > {t("buttons.export")} ); }; Export.displayName = "Export"; export const Socials = () => { const { t } = useI18n(); return ( <> GitHub {t("labels.followUs")} {t("labels.discordChat")} ); }; Socials.displayName = "Socials"; export const LiveCollaborationTrigger = ({ onSelect, isCollaborating, }: { onSelect: () => void; isCollaborating: boolean; }) => { const { t } = useI18n(); return ( {t("labels.liveCollaboration")} ); }; LiveCollaborationTrigger.displayName = "LiveCollaborationTrigger";