Skip to content

Commit

Permalink
fix: command palette tweaks and fixes (excalidraw#7876)
Browse files Browse the repository at this point in the history
  • Loading branch information
dwelle committed Apr 11, 2024
1 parent 30cd536 commit 014848b
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 39 deletions.
15 changes: 15 additions & 0 deletions excalidraw-app/App.tsx
Expand Up @@ -121,6 +121,7 @@ import {
usersIcon,
exportToPlus,
share,
youtubeIcon,
} from "../packages/excalidraw/components/icons";
import { appThemeAtom, useHandleAppTheme } from "./useHandleAppTheme";

Expand Down Expand Up @@ -1140,6 +1141,20 @@ const ExcalidrawWrapper = () => {
);
},
},
{
label: "YouTube",
icon: youtubeIcon,
category: DEFAULT_CATEGORIES.links,
predicate: true,
keywords: ["features", "tutorials", "howto", "help", "community"],
perform: () => {
window.open(
"https://youtube.com/@excalidraw",
"_blank",
"noopener noreferrer",
);
},
},
...(isExcalidrawPlusSignedUser
? [
{
Expand Down
21 changes: 18 additions & 3 deletions excalidraw-app/components/AppMainMenu.tsx
@@ -1,6 +1,11 @@
import React from "react";
import {
arrowBarToLeftIcon,
ExcalLogo,
} from "../../packages/excalidraw/components/icons";
import { Theme } from "../../packages/excalidraw/element/types";
import { MainMenu } from "../../packages/excalidraw/index";
import { isExcalidrawPlusSignedUser } from "../app_constants";
import { LanguageList } from "./LanguageList";

export const AppMainMenu: React.FC<{
Expand All @@ -22,19 +27,29 @@ export const AppMainMenu: React.FC<{
onSelect={() => props.onCollabDialogOpen()}
/>
)}
<MainMenu.DefaultItems.CommandPalette />
<MainMenu.DefaultItems.CommandPalette className="highlighted" />
<MainMenu.DefaultItems.Help />
<MainMenu.DefaultItems.ClearCanvas />
<MainMenu.Separator />
<MainMenu.ItemLink
icon={ExcalLogo}
href={`${
import.meta.env.VITE_APP_PLUS_LP
import.meta.env.VITE_APP_PLUS_APP
}/plus?utm_source=excalidraw&utm_medium=app&utm_content=hamburger`}
className="ExcalidrawPlus"
className=""
>
Excalidraw+
</MainMenu.ItemLink>
<MainMenu.DefaultItems.Socials />
<MainMenu.ItemLink
icon={arrowBarToLeftIcon}
href={`${import.meta.env.VITE_APP_PLUS_APP}${
isExcalidrawPlusSignedUser ? "" : "/sign-up"
}?utm_source=signin&utm_medium=app&utm_content=hamburger`}
className="highlighted"
>
{isExcalidrawPlusSignedUser ? "Sign in" : "Sign up"}
</MainMenu.ItemLink>
<MainMenu.Separator />
<MainMenu.DefaultItems.ToggleTheme
allowSystemTheme
Expand Down
4 changes: 3 additions & 1 deletion excalidraw-app/components/AppWelcomeScreen.tsx
@@ -1,4 +1,5 @@
import React from "react";
import { arrowBarToLeftIcon } from "../../packages/excalidraw/components/icons";
import { useI18n } from "../../packages/excalidraw/i18n";
import { WelcomeScreen } from "../../packages/excalidraw/index";
import { isExcalidrawPlusSignedUser } from "../app_constants";
Expand Down Expand Up @@ -60,8 +61,9 @@ export const AppWelcomeScreen: React.FC<{
import.meta.env.VITE_APP_PLUS_LP
}/plus?utm_source=excalidraw&utm_medium=app&utm_content=welcomeScreenGuest`}
shortcut={null}
icon={arrowBarToLeftIcon}
>
Try Excalidraw Plus!
Sign up
</WelcomeScreen.Center.MenuItemLink>
)}
</WelcomeScreen.Center.Menu>
Expand Down
2 changes: 1 addition & 1 deletion excalidraw-app/index.scss
Expand Up @@ -38,7 +38,7 @@
background-color: #ecfdf5;
color: #064e3c;
}
&.ExcalidrawPlus {
&.highlighted {
color: var(--color-promo);
}
}
Expand Down
25 changes: 8 additions & 17 deletions excalidraw-app/tests/__snapshots__/MobileMenu.test.tsx.snap
Expand Up @@ -216,40 +216,31 @@ exports[`Test MobileMenu > should initialize with welcome screen and hide once u
stroke-width="2"
viewBox="0 0 24 24"
>
<g
stroke-width="1.5"
>
<g>
<path
d="M0 0h24v24H0z"
fill="none"
stroke="none"
/>
<rect
height="4"
rx="1"
width="18"
x="3"
y="8"
<path
d="M10 12l10 0"
/>
<line
x1="12"
x2="12"
y1="8"
y2="21"
<path
d="M10 12l4 4"
/>
<path
d="M19 12v7a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-7"
d="M10 12l4 -4"
/>
<path
d="M7.5 8a2.5 2.5 0 0 1 0 -5a4.8 8 0 0 1 4.5 5a4.8 8 0 0 1 4.5 -5a2.5 2.5 0 0 1 0 5"
d="M4 4l0 16"
/>
</g>
</svg>
</div>
<div
class="welcome-screen-menu-item__text"
>
Try Excalidraw Plus!
Sign up
</div>
</a>
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/excalidraw/analytics.ts
@@ -1,6 +1,6 @@
// place here categories that you want to track. We want to track just a
// small subset of categories at a given time.
const ALLOWED_CATEGORIES_TO_TRACK = ["ai"] as string[];
const ALLOWED_CATEGORIES_TO_TRACK = ["ai", "command_palette"] as string[];

export const trackEvent = (
category: string,
Expand Down
38 changes: 28 additions & 10 deletions packages/excalidraw/components/CommandPalette/CommandPalette.tsx
Expand Up @@ -49,6 +49,8 @@ import { jotaiStore } from "../../jotai";
import { activeConfirmDialogAtom } from "../ActiveConfirmDialog";
import { CommandPaletteItem } from "./types";
import * as defaultItems from "./defaultCommandPaletteItems";
import { trackEvent } from "../../analytics";
import { useStable } from "../../hooks/useStable";

import "./CommandPalette.scss";

Expand Down Expand Up @@ -130,12 +132,20 @@ export const CommandPalette = Object.assign(
if (isCommandPaletteToggleShortcut(event)) {
event.preventDefault();
event.stopPropagation();
setAppState((appState) => ({
openDialog:
setAppState((appState) => {
const nextState =
appState.openDialog?.name === "commandPalette"
? null
: { name: "commandPalette" },
}));
: ({ name: "commandPalette" } as const);

if (nextState) {
trackEvent("command_palette", "open", "shortcut");
}

return {
openDialog: nextState,
};
});
}
};
window.addEventListener(EVENT.KEYDOWN, commandPaletteShortcut, {
Expand Down Expand Up @@ -174,10 +184,20 @@ function CommandPaletteInner({

const inputRef = useRef<HTMLInputElement>(null);

const stableDeps = useStable({
uiAppState,
customCommandPaletteItems,
appProps,
});

useEffect(() => {
if (!uiAppState || !app.scene || !actionManager) {
return;
}
// these props change often and we don't want them to re-run the effect
// which would renew `allCommands`, cascading down and resetting state.
//
// This means that the commands won't update on appState/appProps changes
// while the command palette is open
const { uiAppState, customCommandPaletteItems, appProps } = stableDeps;

const getActionLabel = (action: Action) => {
let label = "";
if (action.label) {
Expand Down Expand Up @@ -533,15 +553,13 @@ function CommandPaletteInner({
);
}
}, [
stableDeps,
app,
appProps,
uiAppState,
actionManager,
setAllCommands,
lastUsed?.label,
setLastUsed,
setAppState,
customCommandPaletteItems,
]);

const [commandSearch, setCommandSearch] = useState("");
Expand Down
17 changes: 13 additions & 4 deletions packages/excalidraw/components/HelpDialog.tsx
Expand Up @@ -4,7 +4,7 @@ import { KEYS } from "../keys";
import { Dialog } from "./Dialog";
import { getShortcutKey } from "../utils";
import "./HelpDialog.scss";
import { ExternalLinkIcon } from "./icons";
import { ExternalLinkIcon, GithubIcon, youtubeIcon } from "./icons";
import { probablySupportsClipboardBlob } from "../clipboard";
import { isDarwin, isFirefox, isWindows } from "../constants";
import { getShortcutFromShortcutName } from "../actions/shortcuts";
Expand All @@ -17,26 +17,35 @@ const Header = () => (
target="_blank"
rel="noopener noreferrer"
>
{t("helpDialog.documentation")}
<div className="HelpDialog__link-icon">{ExternalLinkIcon}</div>
{t("helpDialog.documentation")}
</a>
<a
className="HelpDialog__btn"
href="https://blog.excalidraw.com"
target="_blank"
rel="noopener noreferrer"
>
{t("helpDialog.blog")}
<div className="HelpDialog__link-icon">{ExternalLinkIcon}</div>
{t("helpDialog.blog")}
</a>
<a
className="HelpDialog__btn"
href="https://github.com/excalidraw/excalidraw/issues"
target="_blank"
rel="noopener noreferrer"
>
<div className="HelpDialog__link-icon">{GithubIcon}</div>
{t("helpDialog.github")}
<div className="HelpDialog__link-icon">{ExternalLinkIcon}</div>
</a>
<a
className="HelpDialog__btn"
href="https://youtube.com/@excalidraw"
target="_blank"
rel="noopener noreferrer"
>
<div className="HelpDialog__link-icon">{youtubeIcon}</div>
YouTube
</a>
</div>
);
Expand Down
21 changes: 21 additions & 0 deletions packages/excalidraw/components/icons.tsx
Expand Up @@ -2094,3 +2094,24 @@ export const DeviceDesktopIcon = createIcon(
</g>,
{ ...tablerIconProps, strokeWidth: 1.5 },
);

// arrow-bar-to-left
export const arrowBarToLeftIcon = createIcon(
<g>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M10 12l10 0" />
<path d="M10 12l4 4" />
<path d="M10 12l4 -4" />
<path d="M4 4l0 16" />
</g>,
tablerIconProps,
);

export const youtubeIcon = createIcon(
<g>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M2 8a4 4 0 0 1 4 -4h12a4 4 0 0 1 4 4v8a4 4 0 0 1 -4 4h-12a4 4 0 0 1 -4 -4v-8z" />
<path d="M10 9l5 3l-5 3z" />
</g>,
tablerIconProps,
);
9 changes: 7 additions & 2 deletions packages/excalidraw/components/main-menu/DefaultItems.tsx
Expand Up @@ -39,6 +39,7 @@ 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";

Expand Down Expand Up @@ -122,17 +123,21 @@ export const SaveAsImage = () => {
};
SaveAsImage.displayName = "SaveAsImage";

export const CommandPalette = () => {
export const CommandPalette = (opts?: { className?: string }) => {
const setAppState = useExcalidrawSetAppState();
const { t } = useI18n();

return (
<DropdownMenuItem
icon={boltIcon}
data-testid="command-palette-button"
onSelect={() => setAppState({ openDialog: { name: "commandPalette" } })}
onSelect={() => {
trackEvent("command_palette", "open", "menu");
setAppState({ openDialog: { name: "commandPalette" } });
}}
shortcut={getShortcutFromShortcutName("commandPalette")}
aria-label={t("commandPalette.title")}
className={opts?.className}
>
{t("commandPalette.title")}
</DropdownMenuItem>
Expand Down

0 comments on commit 014848b

Please sign in to comment.