feat: tweak a few icons & add line editor button to side panel (#7990)

pull/7430/head^2
David Luzar 9 months ago committed by GitHub
parent f0d25e34c3
commit d1f37cc64f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,6 +1,6 @@
import React from "react";
import {
arrowBarToLeftIcon,
loginIcon,
ExcalLogo,
} from "../../packages/excalidraw/components/icons";
import { Theme } from "../../packages/excalidraw/element/types";
@ -42,7 +42,7 @@ export const AppMainMenu: React.FC<{
</MainMenu.ItemLink>
<MainMenu.DefaultItems.Socials />
<MainMenu.ItemLink
icon={arrowBarToLeftIcon}
icon={loginIcon}
href={`${import.meta.env.VITE_APP_PLUS_APP}${
isExcalidrawPlusSignedUser ? "" : "/sign-up"
}?utm_source=signin&utm_medium=app&utm_content=hamburger`}

@ -1,5 +1,5 @@
import React from "react";
import { arrowBarToLeftIcon } from "../../packages/excalidraw/components/icons";
import { loginIcon } from "../../packages/excalidraw/components/icons";
import { useI18n } from "../../packages/excalidraw/i18n";
import { WelcomeScreen } from "../../packages/excalidraw/index";
import { isExcalidrawPlusSignedUser } from "../app_constants";
@ -61,7 +61,7 @@ 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}
icon={loginIcon}
>
Sign up
</WelcomeScreen.Center.MenuItemLink>

@ -40,6 +40,10 @@
}
&.highlighted {
color: var(--color-promo);
font-weight: 700;
.dropdown-menu-item__icon g {
stroke-width: 2;
}
}
}
}

@ -216,23 +216,22 @@ exports[`Test MobileMenu > should initialize with welcome screen and hide once u
stroke-width="2"
viewBox="0 0 24 24"
>
<g>
<g
stroke-width="1.5"
>
<path
d="M0 0h24v24H0z"
fill="none"
stroke="none"
/>
<path
d="M10 12l10 0"
/>
<path
d="M10 12l4 4"
d="M15 8v-2a2 2 0 0 0 -2 -2h-7a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h7a2 2 0 0 0 2 -2v-2"
/>
<path
d="M10 12l4 -4"
d="M21 12h-13l3 -3"
/>
<path
d="M4 4l0 16"
d="M11 15l-3 -3"
/>
</g>
</svg>

@ -4,6 +4,9 @@ import { isLinearElement } from "../element/typeChecks";
import { ExcalidrawLinearElement } from "../element/types";
import { StoreAction } from "../store";
import { register } from "./register";
import { ToolButton } from "../components/ToolButton";
import { t } from "../i18n";
import { lineEditorIcon } from "../components/icons";
export const actionToggleLinearEditor = register({
name: "toggleLinearEditor",
@ -11,18 +14,23 @@ export const actionToggleLinearEditor = register({
label: (elements, appState, app) => {
const selectedElement = app.scene.getSelectedElements({
selectedElementIds: appState.selectedElementIds,
includeBoundTextElement: true,
})[0] as ExcalidrawLinearElement;
return appState.editingLinearElement?.elementId === selectedElement?.id
? "labels.lineEditor.exit"
})[0] as ExcalidrawLinearElement | undefined;
return selectedElement?.type === "arrow"
? "labels.lineEditor.editArrow"
: "labels.lineEditor.edit";
},
keywords: ["line"],
trackEvent: {
category: "element",
},
predicate: (elements, appState, _, app) => {
const selectedElements = app.scene.getSelectedElements(appState);
if (selectedElements.length === 1 && isLinearElement(selectedElements[0])) {
if (
!appState.editingLinearElement &&
selectedElements.length === 1 &&
isLinearElement(selectedElements[0])
) {
return true;
}
return false;
@ -45,4 +53,24 @@ export const actionToggleLinearEditor = register({
storeAction: StoreAction.CAPTURE,
};
},
PanelComponent: ({ appState, updateData, app }) => {
const selectedElement = app.scene.getSelectedElements({
selectedElementIds: appState.selectedElementIds,
})[0] as ExcalidrawLinearElement;
const label = t(
selectedElement.type === "arrow"
? "labels.lineEditor.editArrow"
: "labels.lineEditor.edit",
);
return (
<ToolButton
type="button"
icon={lineEditorIcon}
title={label}
aria-label={label}
onClick={() => updateData(null)}
/>
);
},
});

@ -20,6 +20,7 @@ import { StoreAction } from "../store";
export const actionSendBackward = register({
name: "sendBackward",
label: "labels.sendBackward",
keywords: ["move down", "zindex", "layer"],
icon: SendBackwardIcon,
trackEvent: { category: "element" },
perform: (elements, appState) => {
@ -49,6 +50,7 @@ export const actionSendBackward = register({
export const actionBringForward = register({
name: "bringForward",
label: "labels.bringForward",
keywords: ["move up", "zindex", "layer"],
icon: BringForwardIcon,
trackEvent: { category: "element" },
perform: (elements, appState) => {
@ -78,6 +80,7 @@ export const actionBringForward = register({
export const actionSendToBack = register({
name: "sendToBack",
label: "labels.sendToBack",
keywords: ["move down", "zindex", "layer"],
icon: SendToBackIcon,
trackEvent: { category: "element" },
perform: (elements, appState) => {
@ -114,6 +117,7 @@ export const actionSendToBack = register({
export const actionBringToFront = register({
name: "bringToFront",
label: "labels.bringToFront",
keywords: ["move up", "zindex", "layer"],
icon: BringToFrontIcon,
trackEvent: { category: "element" },

@ -23,7 +23,11 @@ import Stack from "./Stack";
import { ToolButton } from "./ToolButton";
import { hasStrokeColor } from "../scene/comparisons";
import { trackEvent } from "../analytics";
import { hasBoundTextElement, isTextElement } from "../element/typeChecks";
import {
hasBoundTextElement,
isLinearElement,
isTextElement,
} from "../element/typeChecks";
import clsx from "clsx";
import { actionToggleZenMode } from "../actions";
import { Tooltip } from "./Tooltip";
@ -114,6 +118,11 @@ export const SelectedShapeActions = ({
const showLinkIcon =
targetElements.length === 1 || isSingleElementBoundContainer;
const showLineEditorAction =
!appState.editingLinearElement &&
targetElements.length === 1 &&
isLinearElement(targetElements[0]);
return (
<div className="panelColumn">
<div>
@ -173,8 +182,8 @@ export const SelectedShapeActions = ({
<div className="buttonList">
{renderAction("sendToBack")}
{renderAction("sendBackward")}
{renderAction("bringToFront")}
{renderAction("bringForward")}
{renderAction("bringToFront")}
</div>
</fieldset>
@ -229,6 +238,7 @@ export const SelectedShapeActions = ({
{renderAction("group")}
{renderAction("ungroup")}
{showLinkIcon && renderAction("hyperlink")}
{showLineEditorAction && renderAction("toggleLinearEditor")}
</div>
</fieldset>
)}
@ -333,8 +343,8 @@ export const ShapesSwitcher = ({
fontSize: 8,
fontFamily: "Cascadia, monospace",
position: "absolute",
background: "pink",
color: "black",
background: "var(--color-promo)",
color: "var(--color-surface-lowest)",
bottom: 3,
right: 4,
}}

@ -258,10 +258,10 @@ function CommandPaletteInner({
actionManager.actions.deleteSelectedElements,
actionManager.actions.copyStyles,
actionManager.actions.pasteStyles,
actionManager.actions.bringToFront,
actionManager.actions.bringForward,
actionManager.actions.sendBackward,
actionManager.actions.sendToBack,
actionManager.actions.bringForward,
actionManager.actions.bringToFront,
actionManager.actions.alignTop,
actionManager.actions.alignBottom,
actionManager.actions.alignLeft,

@ -53,8 +53,8 @@ export const MagicSettings = (props: {
marginLeft: "1rem",
fontSize: 14,
borderRadius: "12px",
color: "#000",
background: "pink",
background: "var(--color-promo)",
color: "var(--color-surface-lowest)",
}}
>
Experimental

@ -253,8 +253,8 @@ export const TTDDialogBase = withInternalFallback(
marginLeft: "10px",
fontSize: 10,
borderRadius: "12px",
background: "pink",
color: "#000",
background: "var(--color-promo)",
color: "var(--color-surface-lowest)",
}}
>
AI Beta

@ -50,10 +50,10 @@ export const DropDownMenuItemBadge = ({
display: "inline-flex",
marginLeft: "auto",
padding: "2px 4px",
background: "pink",
background: "var(--color-promo)",
color: "var(--color-surface-lowest)",
borderRadius: 6,
fontSize: 9,
color: "black",
fontFamily: "Cascadia, monospace",
}}
>

@ -675,119 +675,38 @@ export const resetZoom = createIcon(
{ width: 1024 },
);
export const BringForwardIcon = createIcon(
<>
<g
clipPath="url(#a)"
stroke="currentColor"
strokeWidth="1.25"
strokeLinecap="round"
strokeLinejoin="round"
>
<path
d="M13.889 4.167H8.333c-.767 0-1.389.622-1.389 1.389v5.555c0 .767.622 1.389 1.39 1.389h5.555c.767 0 1.389-.622 1.389-1.389V5.556c0-.767-.622-1.39-1.39-1.39Z"
fill="currentColor"
/>
<path d="M12.5 12.5v1.389a1.389 1.389 0 0 1-1.389 1.389H5.556a1.389 1.389 0 0 1-1.39-1.39V8.334a1.389 1.389 0 0 1 1.39-1.389h1.388" />
const arrowBarToTopJSX = (
<g strokeWidth={1.5}>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 10l0 10" />
<path d="M12 10l4 4" />
<path d="M12 10l-4 4" />
<path d="M4 4l16 0" />
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h20v20H0z" />
</clipPath>
</defs>
</>,
modifiedTablerIconProps,
);
export const SendBackwardIcon = createIcon(
<>
<g
clipPath="url(#a)"
stroke="currentColor"
strokeWidth="1.25"
strokeLinecap="round"
strokeLinejoin="round"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6.944 12.5H12.5v1.389a1.389 1.389 0 0 1-1.389 1.389H5.556a1.389 1.389 0 0 1-1.39-1.39V8.334a1.389 1.389 0 0 1 1.39-1.389h1.388"
fill="currentColor"
/>
<path d="M13.889 4.167H8.333c-.767 0-1.389.621-1.389 1.389v5.555c0 .767.622 1.389 1.39 1.389h5.555c.767 0 1.389-.622 1.389-1.389V5.556c0-.768-.622-1.39-1.39-1.39Z" />
const arrownNarrowUpJSX = (
<g strokeWidth={1.5}>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 5l0 14" />
<path d="M16 9l-4 -4" />
<path d="M8 9l4 -4" />
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h20v20H0z" />
</clipPath>
</defs>
</>,
modifiedTablerIconProps,
);
export const BringToFrontIcon = createIcon(
<>
<g clipPath="url(#a)" stroke="currentColor" strokeWidth="1.25">
<path
d="M8.775 6.458h2.45a2.316 2.316 0 0 1 2.317 2.316v2.452a2.316 2.316 0 0 1-2.316 2.316H8.774a2.316 2.316 0 0 1-2.317-2.316V8.774a2.316 2.316 0 0 1 2.317-2.316Z"
fill="currentColor"
/>
<path d="M5.441 9.792h2.451a2.316 2.316 0 0 1 2.316 2.316v2.45a2.316 2.316 0 0 1-2.316 2.317h-2.45a2.316 2.316 0 0 1-2.317-2.316v-2.451a2.316 2.316 0 0 1 2.316-2.316ZM12.108 3.125h2.45a2.316 2.316 0 0 1 2.317 2.316v2.451a2.316 2.316 0 0 1-2.316 2.316h-2.451a2.316 2.316 0 0 1-2.316-2.316v-2.45a2.316 2.316 0 0 1 2.316-2.317Z" />
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h20v20H0z" />
</clipPath>
</defs>
</>,
modifiedTablerIconProps,
);
export const BringForwardIcon = createIcon(arrownNarrowUpJSX, tablerIconProps);
export const SendToBackIcon = createIcon(
<>
<g clipPath="url(#a)">
<path
d="M5.441 9.792h2.451a2.316 2.316 0 0 1 2.316 2.316v2.45a2.316 2.316 0 0 1-2.316 2.317h-2.45a2.316 2.316 0 0 1-2.317-2.316v-2.451a2.316 2.316 0 0 1 2.316-2.316Z"
stroke="currentColor"
strokeWidth="1.25"
/>
<path
d="M5.441 9.792h2.451a2.316 2.316 0 0 1 2.316 2.316v2.45a2.316 2.316 0 0 1-2.316 2.317h-2.45a2.316 2.316 0 0 1-2.317-2.316v-2.451a2.316 2.316 0 0 1 2.316-2.316Z"
stroke="currentColor"
strokeWidth="1.25"
/>
<mask id="SendToBackIcon" fill="#fff">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.167 5.833v2.06a2.941 2.941 0 0 0 2.94 2.94h2.06v.393a2.941 2.941 0 0 1-2.941 2.94h-.393v-2.058a2.941 2.941 0 0 0-2.94-2.941h-2.06v-.393a2.941 2.941 0 0 1 2.942-2.94h.392Z"
/>
</mask>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.167 5.833v2.06a2.941 2.941 0 0 0 2.94 2.94h2.06v.393a2.941 2.941 0 0 1-2.941 2.94h-.393v-2.058a2.941 2.941 0 0 0-2.94-2.941h-2.06v-.393a2.941 2.941 0 0 1 2.942-2.94h.392Z"
fill="currentColor"
/>
<path
d="M9.167 5.833h1.25v-1.25h-1.25v1.25Zm5 5h1.25v-1.25h-1.25v1.25Zm-3.334 3.334h-1.25v1.25h1.25v-1.25Zm-5-5h-1.25v1.25h1.25v-1.25Zm2.084-3.334v2.06h2.5v-2.06h-2.5Zm0 2.06a4.191 4.191 0 0 0 4.19 4.19v-2.5a1.691 1.691 0 0 1-1.69-1.69h-2.5Zm4.19 4.19h2.06v-2.5h-2.06v2.5Zm.81-1.25v.393h2.5v-.393h-2.5Zm0 .393c0 .933-.758 1.69-1.691 1.69v2.5a4.191 4.191 0 0 0 4.19-4.19h-2.5Zm-1.691 1.69h-.393v2.5h.393v-2.5Zm.857 1.25v-2.058h-2.5v2.059h2.5Zm0-2.058a4.191 4.191 0 0 0-4.19-4.191v2.5c.933 0 1.69.757 1.69 1.69h2.5Zm-4.19-4.191h-2.06v2.5h2.06v-2.5Zm-.81 1.25v-.393h-2.5v.393h2.5Zm0-.393c0-.934.758-1.69 1.692-1.69v-2.5a4.191 4.191 0 0 0-4.192 4.19h2.5Zm1.692-1.69h.392v-2.5h-.392v2.5Z"
fill="currentColor"
mask="url(#SendToBackIcon)"
/>
<path
d="M12.108 3.125h2.45a2.316 2.316 0 0 1 2.317 2.316v2.451a2.316 2.316 0 0 1-2.316 2.316h-2.451a2.316 2.316 0 0 1-2.316-2.316v-2.45a2.316 2.316 0 0 1 2.316-2.317Z"
stroke="currentColor"
strokeWidth="1.25"
/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h20v20H0z" />
</clipPath>
</defs>
</>,
modifiedTablerIconProps,
);
export const SendBackwardIcon = createIcon(arrownNarrowUpJSX, {
...tablerIconProps,
transform: "rotate(180)",
});
export const BringToFrontIcon = createIcon(arrowBarToTopJSX, tablerIconProps);
export const SendToBackIcon = createIcon(arrowBarToTopJSX, {
...tablerIconProps,
transform: "rotate(180)",
});
//
// Align action icons created from scratch to match those of z-index actions
@ -2096,14 +2015,13 @@ export const DeviceDesktopIcon = createIcon(
{ ...tablerIconProps, strokeWidth: 1.5 },
);
// arrow-bar-to-left
export const arrowBarToLeftIcon = createIcon(
<g>
// login
export const loginIcon = createIcon(
<g strokeWidth={1.5}>
<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" />
<path d="M15 8v-2a2 2 0 0 0 -2 -2h-7a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h7a2 2 0 0 0 2 -2v-2" />
<path d="M21 12h-13l3 -3" />
<path d="M11 15l-3 -3" />
</g>,
tablerIconProps,
);
@ -2129,3 +2047,13 @@ export const gridIcon = createIcon(
</g>,
tablerIconProps,
);
export const lineEditorIcon = createIcon(
<g strokeWidth={1.5}>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M17 3m0 1a1 1 0 0 1 1 -1h2a1 1 0 0 1 1 1v2a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1z" />
<path d="M3 17m0 1a1 1 0 0 1 1 -1h2a1 1 0 0 1 1 1v2a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1z" />
<path d="M17 5c-6.627 0 -12 5.373 -12 12" />
</g>,
tablerIconProps,
);

@ -206,10 +206,8 @@
text-decoration: none;
background: var(--button-hover-bg);
.welcome-screen-menu-item__shortcut {
color: var(--color-gray-50);
}
.welcome-screen-menu-item__shortcut,
.welcome-screen-menu-item__icon,
.welcome-screen-menu-item__text {
color: var(--color-gray-100);
}
@ -219,10 +217,8 @@
background: var(--button-hover-bg);
border-color: var(--color-brand-active);
.welcome-screen-menu-item__shortcut {
color: var(--color-gray-50);
}
.welcome-screen-menu-item__shortcut,
.welcome-screen-menu-item__icon,
.welcome-screen-menu-item__text {
color: var(--color-gray-100);
}
@ -249,16 +245,17 @@
.welcome-screen-menu-item:hover {
background-color: var(--color-surface-low);
.welcome-screen-menu-item__shortcut {
color: var(--color-gray-50);
}
.welcome-screen-menu-item__icon,
.welcome-screen-menu-item__shortcut,
.welcome-screen-menu-item__text {
color: var(--color-gray-10);
}
}
.welcome-screen-menu-item:active {
.welcome-screen-menu-item__icon,
.welcome-screen-menu-item__shortcut,
.welcome-screen-menu-item__text {
color: var(--color-gray-10);
}

@ -128,7 +128,7 @@
--color-muted-background: var(--color-gray-80);
--color-muted-background-darker: var(--color-gray-100);
--color-promo: #e70078;
--color-promo: var(--color-primary);
--color-success: #268029;
--color-success-lighter: #cafccc;
@ -236,8 +236,6 @@
--color-muted-background: var(--color-gray-40);
--color-muted-background-darker: var(--color-gray-20);
--color-promo: #d297ff;
--color-logo-text: #e2dfff;
--color-surface-high: hsl(245, 10%, 21%);

@ -129,7 +129,7 @@
},
"lineEditor": {
"edit": "Edit line",
"exit": "Exit line editor"
"editArrow": "Edit arrow"
},
"elementLock": {
"lock": "Lock",

@ -214,7 +214,7 @@ describe("Test Linear Elements", () => {
clientY: midpoint[1],
});
// Enter line editor
let contextMenu = document.querySelector(".context-menu");
const contextMenu = document.querySelector(".context-menu");
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: midpoint[0],
@ -223,23 +223,6 @@ describe("Test Linear Elements", () => {
fireEvent.click(queryByText(contextMenu as HTMLElement, "Edit line")!);
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
// Exiting line editor
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: midpoint[0],
clientY: midpoint[1],
});
contextMenu = document.querySelector(".context-menu");
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: midpoint[0],
clientY: midpoint[1],
});
fireEvent.click(
queryByText(contextMenu as HTMLElement, "Exit line editor")!,
);
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
});
it("should enter line editor when using double clicked with ctrl key", () => {

Loading…
Cancel
Save