Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
Michal Srb 2020-08-13 04:35:31 -07:00 committed by GitHub
parent c9d5ec9277
commit c0dd870c6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 660 additions and 358 deletions

View File

@ -3,7 +3,7 @@ import { KEYS } from "../keys";
import { t } from "../i18n";
import { getShortcutKey } from "../utils";
import { register } from "./register";
import { group, ungroup } from "../components/icons";
import { UngroupIcon, GroupIcon } from "../components/icons";
import { newElementWith } from "../element/mutateElement";
import { getSelectedElements, isSomeElementSelected } from "../scene";
import {
@ -140,7 +140,7 @@ export const actionGroup = register({
<ToolButton
hidden={!enableActionGroup(elements, appState)}
type="button"
icon={group}
icon={<GroupIcon appearance={appState.appearance} />}
onClick={() => updateData(null)}
title={`${t("labels.group")}${getShortcutKey("CtrlOrCmd+G")}`}
aria-label={t("labels.group")}
@ -193,7 +193,7 @@ export const actionUngroup = register({
<ToolButton
type="button"
hidden={getSelectedGroupIds(appState).length === 0}
icon={ungroup}
icon={<UngroupIcon appearance={appState.appearance} />}
onClick={() => updateData(null)}
title={`${t("labels.ungroup")}${getShortcutKey("CtrlOrCmd+Shift+G")}`}
aria-label={t("labels.ungroup")}

View File

@ -10,10 +10,10 @@ import { t } from "../i18n";
import { getShortcutKey } from "../utils";
import { register } from "./register";
import {
sendBackward,
bringToFront,
sendToBack,
bringForward,
SendBackwardIcon,
BringToFrontIcon,
SendToBackIcon,
BringForwardIcon,
} from "../components/icons";
import { ExcalidrawElement } from "../element/types";
import { AppState } from "../types";
@ -86,14 +86,14 @@ export const actionSendBackward = register({
keyPriority: 40,
keyTest: (event) =>
event[KEYS.CTRL_OR_CMD] && !event.shiftKey && event.code === "BracketLeft",
PanelComponent: ({ updateData }) => (
PanelComponent: ({ updateData, appState }) => (
<button
type="button"
className="zIndexButton"
onClick={() => updateData(null)}
title={`${t("labels.sendBackward")}${getShortcutKey("CtrlOrCmd+[")}`}
>
{sendBackward}
<SendBackwardIcon appearance={appState.appearance} />
</button>
),
});
@ -111,14 +111,14 @@ export const actionBringForward = register({
keyPriority: 40,
keyTest: (event) =>
event[KEYS.CTRL_OR_CMD] && !event.shiftKey && event.code === "BracketRight",
PanelComponent: ({ updateData }) => (
PanelComponent: ({ updateData, appState }) => (
<button
type="button"
className="zIndexButton"
onClick={() => updateData(null)}
title={`${t("labels.bringForward")}${getShortcutKey("CtrlOrCmd+]")}`}
>
{bringForward}
<BringForwardIcon appearance={appState.appearance} />
</button>
),
});
@ -140,7 +140,7 @@ export const actionSendToBack = register({
event.shiftKey &&
event.code === "BracketLeft";
},
PanelComponent: ({ updateData }) => (
PanelComponent: ({ updateData, appState }) => (
<button
type="button"
className="zIndexButton"
@ -151,7 +151,7 @@ export const actionSendToBack = register({
: getShortcutKey("CtrlOrCmd+Shift+[")
}`}
>
{sendToBack}
<SendToBackIcon appearance={appState.appearance} />
</button>
),
});
@ -173,7 +173,7 @@ export const actionBringToFront = register({
event.shiftKey &&
event.code === "BracketRight";
},
PanelComponent: ({ updateData }) => (
PanelComponent: ({ updateData, appState }) => (
<button
type="button"
className="zIndexButton"
@ -184,7 +184,7 @@ export const actionBringToFront = register({
: getShortcutKey("CtrlOrCmd+Shift+]")
}`}
>
{bringToFront}
<BringToFrontIcon appearance={appState.appearance} />
</button>
),
});

View File

@ -13,6 +13,7 @@ export const getDefaultAppState = (): Omit<
"offsetTop" | "offsetLeft"
> => {
return {
appearance: "light",
isLoading: false,
errorMessage: null,
draggingElement: null,
@ -83,6 +84,7 @@ const APP_STATE_STORAGE_CONF = (<
>(
config: { [K in keyof T]: K extends keyof AppState ? T[K] : never },
) => config)({
appearance: { browser: true, export: false },
collaborators: { browser: false, export: false },
currentItemBackgroundColor: { browser: true, export: false },
currentItemFillStyle: { browser: true, export: false },

View File

@ -724,6 +724,11 @@ class App extends React.Component<ExcalidrawProps, AppState> {
});
}
document.body.classList.toggle(
"Appearance_dark",
this.state.appearance === "dark",
);
if (this.state.isCollaborating && !this.portal.socket) {
this.initializeSocketClient({ showLoadingState: true });
}

View File

@ -0,0 +1,26 @@
import React from "react";
import { ActionManager } from "../actions/manager";
import { AppState } from "../types";
import { DarkModeToggle } from "./DarkModeToggle";
export const BackgroundPickerAndDarkModeToggle = ({
appState,
setAppState,
actionManager,
}: {
actionManager: ActionManager;
appState: AppState;
setAppState: any;
}) => (
<div style={{ display: "flex" }}>
{actionManager.renderAction("changeViewBackgroundColor")}
<div style={{ marginInlineStart: "0.25rem" }}>
<DarkModeToggle
value={appState.appearance}
onChange={(appearance) => {
setAppState({ appearance });
}}
/>
</div>
</div>
);

View File

@ -1,7 +1,7 @@
@import "open-color/open-color.scss";
.color-picker {
background: $oc-white;
background: var(--popup-background-color);
border: 0px solid transparentize($oc-white, 0.75);
box-shadow: transparentize($oc-black, 0.75) 0px 1px 4px;
border-radius: 4px;
@ -25,7 +25,7 @@
height: 0px;
border-style: solid;
border-width: 0px 9px 10px;
border-color: transparent transparent $oc-white;
border-color: transparent transparent var(--popup-background-color);
position: absolute;
top: -10px;
:root[dir="ltr"] & {
@ -62,12 +62,13 @@
box-sizing: border-box;
border: 1px solid #ddd;
background-color: currentColor !important;
filter: var(--appearance-filter);
}
.color-picker-swatch:focus {
/* TODO: only show the border when the color is too light to see as a shadow */
box-shadow: 0 0 4px 1px currentColor;
border-color: $oc-blue-5;
border-color: var(--select-highlight-color);
}
.color-picker-transparent {
@ -86,7 +87,7 @@
}
.color-picker-hash {
background: $oc-gray-3;
background: var(--input-border-color);
height: 1.875rem;
width: 1.875rem;
:root[dir="ltr"] & {
@ -95,14 +96,14 @@
:root[dir="rtl"] & {
border-radius: 0px 4px 4px 0px;
}
color: $oc-gray-7;
color: var(--input-label-color);
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.color-input-container:focus-within .color-picker-hash {
box-shadow: 0 0 0 2px $oc-blue-2;
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
.color-input-container:focus-within .color-picker-hash::before,
.color-input-container:focus-within .color-picker-hash::after {
@ -113,7 +114,7 @@
top: 0;
}
.color-input-container:focus-within .color-picker-hash::before {
background: $oc-gray-3;
background: var(--input-border-color);
:root[dir="ltr"] & {
right: -1px;
}
@ -122,7 +123,7 @@
}
}
.color-input-container:focus-within .color-picker-hash::after {
background: #fff;
background: var(--input-background-color);
:root[dir="ltr"] & {
right: -2px;
}
@ -139,11 +140,12 @@
width: 12ch; /* length of `transparent` + 1 */
margin: 0;
font-size: 1rem;
color: $oc-gray-8;
background-color: var(--input-background-color);
color: var(--text-color-primary);
border: 0px;
outline: none;
height: 1.75em;
box-shadow: $oc-gray-3 0px 0px 0px 1px inset;
box-shadow: var(--input-border-color) 0px 0px 0px 1px inset;
:root[dir="ltr"] & {
border-radius: 0px 4px 4px 0px;
}
@ -164,6 +166,7 @@
position: relative;
overflow: hidden;
background-color: transparent !important;
filter: var(--appearance-filter);
}
.color-picker-label-swatch::after {
@ -186,5 +189,25 @@
left: 2px;
}
font-size: 0.7em;
color: #ccc;
}
.color-picker-type-canvasBackground .color-picker-keybinding {
color: #aaa;
}
.color-picker-type-elementBackground .color-picker-keybinding {
color: #fff;
.Appearance_dark & {
color: #000;
}
}
.color-picker-swatch[aria-label="transparent"] .color-picker-keybinding {
color: #aaa;
.Appearance_dark & {
color: #000;
}
}
.color-picker-type-elementStroke .color-picker-keybinding {
color: #d4d4d4;
}

View File

@ -43,6 +43,7 @@ const Picker = ({
onClose,
label,
showInput = true,
type,
}: {
colors: string[];
color: string | null;
@ -50,6 +51,7 @@ const Picker = ({
onClose: () => void;
label: string;
showInput: boolean;
type: "canvasBackground" | "elementBackground" | "elementStroke";
}) => {
const firstItem = React.useRef<HTMLButtonElement>();
const activeItem = React.useRef<HTMLButtonElement>();
@ -123,7 +125,7 @@ const Picker = ({
return (
<div
className="color-picker"
className={`color-picker color-picker-type-${type}`}
role="dialog"
aria-modal="true"
aria-label={t("labels.colorPicker")}
@ -290,6 +292,7 @@ export const ColorPicker = ({
}}
label={label}
showInput={false}
type={type}
/>
</Popover>
) : null}

View File

@ -9,8 +9,12 @@
user-select: none;
margin: -0.25rem 0 0 0.125rem;
padding: 0.25rem 0;
background-color: $oc-gray-1;
border: 1px solid $oc-gray-5;
background-color: var(--popup-secondary-background-color);
border: 1px solid var(--button-gray-3);
}
.context-menu button {
color: var(--popup-text-color);
}
.context-menu-option {
@ -27,8 +31,8 @@
}
.context-menu-option:hover {
color: $oc-white;
background-color: $oc-blue-5;
color: var(--popup-background-color);
background-color: var(--select-highlight-color);
}
.context-menu-option:focus {

View File

@ -0,0 +1,52 @@
import "./ToolIcon.scss";
import React from "react";
import { t } from "../i18n";
export type Appearence = "light" | "dark";
// We chose to use only explicit toggle and not a third option for system value,
// but this could be added in the future.
export const DarkModeToggle = (props: {
value: Appearence;
onChange: (value: Appearence) => void;
}) => {
return (
<label
className={`ToolIcon ToolIcon__lock ToolIcon_type_floating ToolIcon_size_M`}
title={t("buttons.toggleDarkMode")}
>
<input
className="ToolIcon_type_checkbox ToolIcon_toggle_opaque"
type="checkbox"
onChange={(event) =>
props.onChange(event.target.checked ? "dark" : "light")
}
checked={props.value === "dark"}
aria-label={t("buttons.toggleDarkMode")}
/>
<div className="ToolIcon__icon">
{props.value === "light" ? ICONS.MOON : ICONS.SUN}
</div>
</label>
);
};
const ICONS = {
SUN: (
<svg width="512" height="512" className="rtl-mirror" viewBox="0 0 512 512">
<path
fill="currentColor"
d="M256 160c-52.9 0-96 43.1-96 96s43.1 96 96 96 96-43.1 96-96-43.1-96-96-96zm246.4 80.5l-94.7-47.3 33.5-100.4c4.5-13.6-8.4-26.5-21.9-21.9l-100.4 33.5-47.4-94.8c-6.4-12.8-24.6-12.8-31 0l-47.3 94.7L92.7 70.8c-13.6-4.5-26.5 8.4-21.9 21.9l33.5 100.4-94.7 47.4c-12.8 6.4-12.8 24.6 0 31l94.7 47.3-33.5 100.5c-4.5 13.6 8.4 26.5 21.9 21.9l100.4-33.5 47.3 94.7c6.4 12.8 24.6 12.8 31 0l47.3-94.7 100.4 33.5c13.6 4.5 26.5-8.4 21.9-21.9l-33.5-100.4 94.7-47.3c13-6.5 13-24.7.2-31.1zm-155.9 106c-49.9 49.9-131.1 49.9-181 0-49.9-49.9-49.9-131.1 0-181 49.9-49.9 131.1-49.9 181 0 49.9 49.9 49.9 131.1 0 181z"
></path>
</svg>
),
MOON: (
<svg width="512" height="512" className="rtl-mirror" viewBox="0 0 512 512">
<path
fill="currentColor"
d="M283.211 512c78.962 0 151.079-35.925 198.857-94.792 7.068-8.708-.639-21.43-11.562-19.35-124.203 23.654-238.262-71.576-238.262-196.954 0-72.222 38.662-138.635 101.498-174.394 9.686-5.512 7.25-20.197-3.756-22.23A258.156 258.156 0 0 0 283.211 0c-141.309 0-256 114.511-256 256 0 141.309 114.511 256 256 256z"
></path>
</svg>
),
};

View File

@ -13,6 +13,7 @@
}
.Dialog .Modal__close {
color: var(--icon-fill-color);
margin: 0;
}
@ -34,11 +35,11 @@
padding: calc(var(--space-factor) * 2);
padding-left: var(--inset-left);
padding-right: var(--inset-right);
background: white;
background: var(--bg-color-island);
font-size: 1.25em;
box-sizing: border-box;
border-bottom: 1px solid $oc-gray-4;
border-bottom: 1px solid var(--button-gray-2);
z-index: 1;
}
.Dialog__titleContent {

View File

@ -15,6 +15,10 @@
max-height: 25rem;
}
.Appearance_dark .ExportDialog__preview canvas {
filter: none;
}
.ExportDialog__actions {
width: 100%;
display: flex;
@ -26,6 +30,10 @@
.ExportDialog__name {
grid-column: project-name;
margin: auto;
.TextInput {
height: calc(1rem - 3px);
}
}
@media (max-width: 550px) {

View File

@ -2,32 +2,37 @@ import React from "react";
import oc from "open-color";
// https://github.com/tholman/github-corners
export const GitHubCorner = React.memo(() => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 250 250"
className="github-corner rtl-mirror"
>
<a
href="https://github.com/excalidraw/excalidraw"
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub repository"
export const GitHubCorner = React.memo(
({ appearance }: { appearance: "light" | "dark" }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 250 250"
className="github-corner rtl-mirror"
>
<path d="M0 0l115 115h15l12 27 108 108V0z" fill={oc.gray[6]} />
<path
className="octo-arm"
d="M128 109c-15-9-9-19-9-19 3-7 2-11 2-11-1-7 3-2 3-2 4 5 2 11 2 11-3 10 5 15 9 16"
style={{ transformOrigin: "130px 106px" }}
fill={oc.white}
/>
<path
className="octo-body"
d="M115 115s4 2 5 0l14-14c3-2 6-3 8-3-8-11-15-24 2-41 5-5 10-7 16-7 1-2 3-7 12-11 0 0 5 3 7 16 4 2 8 5 12 9s7 8 9 12c14 3 17 7 17 7-4 8-9 11-11 11 0 6-2 11-7 16-16 16-30 10-41 2 0 3-1 7-5 11l-12 11c-1 1 1 5 1 5z"
fill={oc.white}
/>
</a>
</svg>
));
<a
href="https://github.com/excalidraw/excalidraw"
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub repository"
>
<path
d="M0 0l115 115h15l12 27 108 108V0z"
fill={appearance === "light" ? oc.gray[6] : oc.gray[8]}
/>
<path
className="octo-arm"
d="M128 109c-15-9-9-19-9-19 3-7 2-11 2-11-1-7 3-2 3-2 4 5 2 11 2 11-3 10 5 15 9 16"
style={{ transformOrigin: "130px 106px" }}
fill={appearance === "light" ? oc.white : oc.black}
/>
<path
className="octo-body"
d="M115 115s4 2 5 0l14-14c3-2 6-3 8-3-8-11-15-24 2-41 5-5 10-7 16-7 1-2 3-7 12-11 0 0 5 3 7 16 4 2 8 5 12 9s7 8 9 12c14 3 17 7 17 7-4 8-9 11-11 11 0 6-2 11-7 16-16 16-30 10-41 2 0 3-1 7-5 11l-12 11c-1 1 1 5 1 5z"
fill={appearance === "light" ? oc.white : oc.black}
/>
</a>
</svg>
),
);

View File

@ -17,7 +17,7 @@
}
> span {
background-color: transparentize($oc-white, 0.12);
background-color: var(--overlay-background-color);
padding: 0.2rem 0.4rem;
border-radius: 3px;
}

View File

@ -98,6 +98,7 @@
&__footer {
position: absolute;
z-index: 100;
bottom: 0px;
:root[dir="ltr"] & {
right: 0;

View File

@ -43,6 +43,7 @@ import { loadLibrary, saveLibrary } from "../data/localStorage";
import { ToolButton } from "./ToolButton";
import { saveLibraryAsJSON, importLibraryFromJSON } from "../data/json";
import { muteFSAbortError } from "../utils";
import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
interface LayerUIProps {
actionManager: ActionManager;
@ -372,7 +373,11 @@ const LayerUI = ({
onRoomDestroy={onRoomDestroy}
/>
</Stack.Row>
{actionManager.renderAction("changeViewBackgroundColor")}
<BackgroundPickerAndDarkModeToggle
actionManager={actionManager}
appState={appState}
setAppState={setAppState}
/>
</Stack.Col>
</Island>
</Section>
@ -580,7 +585,7 @@ const LayerUI = ({
zenModeEnabled && "transition-right"
}`}
>
<GitHubCorner />
<GitHubCorner appearance={appState.appearance} />
</aside>
}
{renderFooter()}

View File

@ -1,6 +1,6 @@
.library-unit {
align-items: center;
border: 1px solid #ccc;
border: 1px solid var(--button-gray-2);
display: flex;
justify-content: center;
position: relative;
@ -15,6 +15,7 @@
}
.library-unit__dragger > svg {
filter: var(--appearance-filter);
flex-grow: 1;
max-height: 100%;
max-width: 100%;
@ -26,6 +27,7 @@
align-items: center;
background: none;
border: none;
color: var(--icon-fill-color);
display: flex;
justify-content: center;
margin: 0;

View File

@ -10,7 +10,10 @@ import { LibraryItem } from "../types";
// fa-plus
const PLUS_ICON = (
<svg viewBox="0 0 1792 1792">
<path d="M1600 736v192q0 40-28 68t-68 28h-416v416q0 40-28 68t-68 28h-192q-40 0-68-28t-28-68v-416h-416q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h416v-416q0-40 28-68t68-28h192q40 0 68 28t28 68v416h416q40 0 68 28t28 68z" />
<path
fill="currentColor"
d="M1600 736v192q0 40-28 68t-68 28h-416v416q0 40-28 68t-68 28h-192q-40 0-68-28t-28-68v-416h-416q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h416v-416q0-40 28-68t68-28h192q40 0 68 28t28 68v416h416q40 0 68 28t28 68z"
/>
</svg>
);

View File

@ -17,6 +17,7 @@ import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
import { LockIcon } from "./LockIcon";
import { LoadingMessage } from "./LoadingMessage";
import { UserList } from "./UserList";
import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
type MobileMenuProps = {
appState: AppState;
@ -100,7 +101,11 @@ export const MobileMenu = ({
onRoomCreate={onRoomCreate}
onRoomDestroy={onRoomDestroy}
/>
{actionManager.renderAction("changeViewBackgroundColor")}
<BackgroundPickerAndDarkModeToggle
actionManager={actionManager}
appState={appState}
setAppState={setAppState}
/>
<fieldset>
<legend>{t("labels.language")}</legend>
<LanguageList

View File

@ -36,7 +36,7 @@
position: relative;
// for modals, reset blurry bg
background: #fff;
background: var(--bg-color-island);
backdrop-filter: none;
@media #{$media-query} {

View File

@ -1,8 +1,11 @@
@import "../css/_variables";
.RoomDialog-modalButton.is-collaborating {
background-color: $oc-green-0;
color: $oc-green-9;
background-color: var(--button-special-active-background-color);
.ToolIcon__icon svg {
color: var(--icon-green-fill-color);
}
}
.RoomDialog-modalButton-collaborators {
@ -24,6 +27,7 @@
}
.RoomDialog-link {
color: var(--text-color-primary);
min-width: 0;
flex: 1 1 auto;
margin-left: 1em;
@ -47,6 +51,8 @@
}
.RoomDialog-username {
background-color: var(--input-background-color);
border-color: var(--input-border-color);
appearance: none;
min-width: 0;
flex: 1 1 auto;
@ -63,6 +69,10 @@
}
.RoomDialog-stopSession {
background-color: $oc-red-1;
color: $oc-red-9;
background-color: var(--button-destructive-background-color);
.ToolIcon__label,
.ToolIcon__icon svg {
color: var(--button-destructive-color);
}
}

View File

@ -0,0 +1,40 @@
@import "../css/_variables";
.ShortcutsDialog-island {
border: 1px solid var(--button-gray-2);
margin-bottom: 16px;
}
.ShortcutsDialog-island-title {
margin: 0;
padding: 4px;
background-color: var(--button-gray-1);
text-align: center;
}
.ShorcutsDialog-shortcut {
border-top: 1px solid var(--button-gray-2);
}
.ShorcutsDialog-key {
word-break: keep-all;
border: 1px solid var(--button-gray-2);
padding: 2px 8px;
margin: auto 4px;
background-color: var(--button-gray-1);
border-radius: 2px;
font-size: 0.8em;
min-height: 26px;
box-sizing: border-box;
display: flex;
align-items: center;
}
.ShortcutsDialog-footer {
display: flex;
flex-direction: row;
justify-content: space-evenly;
border-top: 1px solid var(--button-gray-2);
margin-top: 8px;
padding-top: 16px;
}

View File

@ -1,9 +1,9 @@
import React from "react";
import oc from "open-color";
import { t } from "../i18n";
import { isDarwin } from "../keys";
import { Dialog } from "./Dialog";
import { getShortcutKey } from "../utils";
import "./ShortcutsDialog.scss";
const Columns = (props: { children: React.ReactNode }) => (
<div
@ -19,35 +19,15 @@ const Columns = (props: { children: React.ReactNode }) => (
);
const Column = (props: { children: React.ReactNode }) => (
<div
style={{
width: "49%",
}}
>
{props.children}
</div>
<div style={{ width: "49%" }}>{props.children}</div>
);
const ShortcutIsland = (props: {
caption: string;
children: React.ReactNode;
}) => (
<div
style={{
border: `1px solid ${oc.gray[4]}`,
marginBottom: "16px",
}}
>
<h3
style={{
margin: "0",
padding: "4px",
backgroundColor: oc.gray[2],
textAlign: "center",
}}
>
{props.caption}
</h3>
<div className="ShortcutsDialog-island">
<h3 className="ShortcutsDialog-island-title">{props.caption}</h3>
{props.children}
</div>
);
@ -59,11 +39,7 @@ const Shortcut = (props: {
}) => {
const isRTL = document.documentElement.getAttribute("dir") === "rtl";
return (
<div
style={{
borderTop: `1px solid ${oc.gray[4]}`,
}}
>
<div className="ShorcutsDialog-shortcut">
<div
style={{
display: "flex",
@ -108,35 +84,11 @@ Shortcut.defaultProps = {
};
const ShortcutKey = (props: { children: React.ReactNode }) => (
<span
style={{
wordBreak: "keep-all",
border: `1px solid ${oc.gray[4]}`,
padding: "2px 8px",
margin: "auto 4px",
backgroundColor: oc.gray[2],
borderRadius: "2px",
fontSize: "0.8em",
minHeight: "26px",
boxSizing: "border-box",
display: "flex",
alignItems: "center",
}}
{...props}
/>
<span className="ShorcutsDialog-key" {...props} />
);
const Footer = () => (
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-evenly",
borderTop: `1px solid ${oc.gray[4]}`,
marginTop: 8,
paddingTop: 16,
}}
>
<div className="ShortcutsDialog-footer">
<a
href="https://blog.excalidraw.com"
target="_blank"

View File

@ -1,20 +1,21 @@
@import "../css/_variables.scss";
.TextInput {
color: var(--text-color-primary);
display: inline-block;
border: 1.5px solid $oc-gray-2;
border: 1.5px solid var(--button-gray-1);
line-height: 1;
padding: 0.75rem;
white-space: nowrap;
border-radius: var(--space-factor);
background-color: $oc-white;
background-color: var(--input-background-color);
&:not(:focus) {
&:hover {
background-color: $oc-gray-1;
background-color: var(--input-hover-background-color);
}
}
&:focus {
outline: none;
box-shadow: 0 0 0 2px $oc-blue-5;
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
}

View File

@ -1,12 +1,5 @@
@import "open-color/open-color.scss";
:root {
--button-gray-1: #{$oc-gray-2};
--button-gray-2: #{$oc-gray-4};
--button-gray-3: #{$oc-gray-5};
--button-blue: #{$oc-blue-2};
}
.ToolIcon {
display: inline-flex;
align-items: center;
@ -21,6 +14,7 @@
.ToolIcon__icon {
width: 2.5rem;
height: 2.5rem;
color: var(--icon-fill-color);
display: flex;
justify-content: center;
@ -31,6 +25,8 @@
svg {
position: relative;
height: 1em;
fill: var(--icon-fill-color);
color: var(--icon-fill-color);
}
& + .ToolIcon__label {
@ -39,6 +35,7 @@
}
.ToolIcon__label {
color: var(--icon-fill-color);
font-family: var(--ui-font);
margin: 0 0.8em;
text-overflow: ellipsis;
@ -63,7 +60,7 @@
background-color: var(--button-gray-2);
}
&:focus {
box-shadow: 0 0 0 2px var(--button-blue);
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
&.ToolIcon--selected {
background-color: var(--button-gray-2);
@ -86,11 +83,11 @@
opacity: 0;
pointer-events: none;
&:checked + .ToolIcon__icon {
&:not(.ToolIcon_toggle_opaque):checked + .ToolIcon__icon {
background-color: var(--button-gray-2);
}
&:focus + .ToolIcon__icon {
box-shadow: 0 0 0 2px var(--button-blue);
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
&:active + .ToolIcon__icon {
background-color: var(--button-gray-3);
@ -125,7 +122,7 @@
bottom: 2px;
right: 3px;
font-size: 0.5em;
color: var(--button-gray-3);
color: var(--keybinding-color);
font-family: var(--ui-font);
user-select: none;
}

View File

@ -7,7 +7,13 @@ import React from "react";
import oc from "open-color";
const ACTIVE_ELEMENT_COLOR = oc.orange[4];
const activeElementColor = (appearance: "light" | "dark") =>
appearance === "light" ? oc.orange[4] : oc.orange[9];
const iconFillColor = (appearance: "light" | "dark") =>
appearance === "light" ? oc.black : oc.gray[4];
const handlerColor = (appearance: "light" | "dark") =>
appearance === "light" ? oc.white : "#1e1e1e";
type Opts = { width?: number; height?: number; mirror?: true } & React.SVGProps<
SVGSVGElement
>;
@ -109,74 +115,90 @@ export const resetZoom = createIcon(
{ width: 1024 },
);
export const bringForward = createIcon(
<>
<path
d="M22 9.556C22 8.696 21.303 8 20.444 8H16v8H8v4.444C8 21.304 8.697 22 9.556 22h10.888c.86 0 1.556-.697 1.556-1.556V9.556z"
stroke={oc.black}
strokeWidth="2"
/>
<path
d="M16 3.556C16 2.696 15.303 2 14.444 2H3.556C2.696 2 2 2.697 2 3.556v10.888C2 15.304 2.697 16 3.556 16h10.888c.86 0 1.556-.697 1.556-1.556V3.556z"
fill={ACTIVE_ELEMENT_COLOR}
stroke={ACTIVE_ELEMENT_COLOR}
strokeWidth="2"
/>
</>,
{ width: 24 },
export const BringForwardIcon = React.memo(
({ appearance }: { appearance: "light" | "dark" }) =>
createIcon(
<>
<path
d="M22 9.556C22 8.696 21.303 8 20.444 8H16v8H8v4.444C8 21.304 8.697 22 9.556 22h10.888c.86 0 1.556-.697 1.556-1.556V9.556z"
fill={iconFillColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="2"
/>
<path
d="M16 3.556C16 2.696 15.303 2 14.444 2H3.556C2.696 2 2 2.697 2 3.556v10.888C2 15.304 2.697 16 3.556 16h10.888c.86 0 1.556-.697 1.556-1.556V3.556z"
fill={activeElementColor(appearance)}
stroke={activeElementColor(appearance)}
strokeWidth="2"
/>
</>,
{ width: 24 },
),
);
export const sendBackward = createIcon(
<>
<path
d="M16 3.556C16 2.696 15.303 2 14.444 2H3.556C2.696 2 2 2.697 2 3.556v10.888C2 15.304 2.697 16 3.556 16h10.888c.86 0 1.556-.697 1.556-1.556V3.556z"
fill={ACTIVE_ELEMENT_COLOR}
stroke={ACTIVE_ELEMENT_COLOR}
strokeWidth="2"
/>
<path
d="M22 9.556C22 8.696 21.303 8 20.444 8H9.556C8.696 8 8 8.697 8 9.556v10.888C8 21.304 8.697 22 9.556 22h10.888c.86 0 1.556-.697 1.556-1.556V9.556z"
stroke={oc.black}
strokeWidth="2"
/>
</>,
{ width: 24 },
export const SendBackwardIcon = React.memo(
({ appearance }: { appearance: "light" | "dark" }) =>
createIcon(
<>
<path
d="M16 3.556C16 2.696 15.303 2 14.444 2H3.556C2.696 2 2 2.697 2 3.556v10.888C2 15.304 2.697 16 3.556 16h10.888c.86 0 1.556-.697 1.556-1.556V3.556z"
fill={activeElementColor(appearance)}
stroke={activeElementColor(appearance)}
strokeWidth="2"
/>
<path
d="M22 9.556C22 8.696 21.303 8 20.444 8H9.556C8.696 8 8 8.697 8 9.556v10.888C8 21.304 8.697 22 9.556 22h10.888c.86 0 1.556-.697 1.556-1.556V9.556z"
fill={iconFillColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="2"
/>
</>,
{ width: 24 },
),
);
export const bringToFront = createIcon(
<>
<path
d="M13 21a1 1 0 001 1h7a1 1 0 001-1v-7a1 1 0 00-1-1h-3v5h-5v3zM11 3a1 1 0 00-1-1H3a1 1 0 00-1 1v7a1 1 0 001 1h3V6h5V3z"
stroke={oc.black}
strokeWidth="2"
/>
<path
d="M18 7.333C18 6.597 17.403 6 16.667 6H7.333C6.597 6 6 6.597 6 7.333v9.334C6 17.403 6.597 18 7.333 18h9.334c.736 0 1.333-.597 1.333-1.333V7.333z"
fill={ACTIVE_ELEMENT_COLOR}
stroke={ACTIVE_ELEMENT_COLOR}
strokeWidth="2"
/>
</>,
{ width: 24 },
export const BringToFrontIcon = React.memo(
({ appearance }: { appearance: "light" | "dark" }) =>
createIcon(
<>
<path
d="M13 21a1 1 0 001 1h7a1 1 0 001-1v-7a1 1 0 00-1-1h-3v5h-5v3zM11 3a1 1 0 00-1-1H3a1 1 0 00-1 1v7a1 1 0 001 1h3V6h5V3z"
fill={iconFillColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="2"
/>
<path
d="M18 7.333C18 6.597 17.403 6 16.667 6H7.333C6.597 6 6 6.597 6 7.333v9.334C6 17.403 6.597 18 7.333 18h9.334c.736 0 1.333-.597 1.333-1.333V7.333z"
fill={activeElementColor(appearance)}
stroke={activeElementColor(appearance)}
strokeWidth="2"
/>
</>,
{ width: 24 },
),
);
export const sendToBack = createIcon(
<>
<path
d="M18 7.333C18 6.597 17.403 6 16.667 6H7.333C6.597 6 6 6.597 6 7.333v9.334C6 17.403 6.597 18 7.333 18h9.334c.736 0 1.333-.597 1.333-1.333V7.333z"
fill={ACTIVE_ELEMENT_COLOR}
stroke={ACTIVE_ELEMENT_COLOR}
strokeLinejoin="round"
strokeWidth="2"
/>
<path
d="M11 3a1 1 0 00-1-1H3a1 1 0 00-1 1v7a1 1 0 001 1h8V3zM22 14a1 1 0 00-1-1h-7a1 1 0 00-1 1v7a1 1 0 001 1h8v-8z"
stroke={oc.black}
strokeLinejoin="round"
strokeWidth="2"
/>
</>,
{ width: 24 },
export const SendToBackIcon = React.memo(
({ appearance }: { appearance: "light" | "dark" }) =>
createIcon(
<>
<path
d="M18 7.333C18 6.597 17.403 6 16.667 6H7.333C6.597 6 6 6.597 6 7.333v9.334C6 17.403 6.597 18 7.333 18h9.334c.736 0 1.333-.597 1.333-1.333V7.333z"
fill={activeElementColor(appearance)}
stroke={activeElementColor(appearance)}
strokeLinejoin="round"
strokeWidth="2"
/>
<path
d="M11 3a1 1 0 00-1-1H3a1 1 0 00-1 1v7a1 1 0 001 1h8V3zM22 14a1 1 0 00-1-1h-7a1 1 0 00-1 1v7a1 1 0 001 1h8v-8z"
fill={iconFillColor(appearance)}
stroke={iconFillColor(appearance)}
strokeLinejoin="round"
strokeWidth="2"
/>
</>,
{ width: 24 },
),
);
export const users = createIcon(
@ -213,127 +235,134 @@ export const shield = createIcon(
{ width: 24 },
);
export const group = createIcon(
<>
<path d="M25 26H111V111H25" fill={oc.black} />
<path
d="M25 111C25 80.2068 25 49.4135 25 26M25 26C48.6174 26 72.2348 26 111 26H25ZM25 26C53.3671 26 81.7343 26 111 26H25ZM111 26C111 52.303 111 78.606 111 111V26ZM111 26C111 51.2947 111 76.5893 111 111V26ZM111 111C87.0792 111 63.1585 111 25 111H111ZM111 111C87.4646 111 63.9293 111 25 111H111ZM25 111C25 81.1514 25 51.3028 25 26V111Z"
stroke={oc.black}
strokeWidth="2"
/>
<path d="M100 100H160V160H100" fill={oc.black} />
<path
d="M100 160C100 144.106 100 128.211 100 100M100 100C117.706 100 135.412 100 160 100H100ZM100 100C114.214 100 128.428 100 160 100H100ZM160 100C160 120.184 160 140.369 160 160V100ZM160 100C160 113.219 160 126.437 160 160V100ZM160 160C145.534 160 131.068 160 100 160H160ZM160 160C143.467 160 126.934 160 100 160H160ZM100 160C100 143.661 100 127.321 100 100V160Z"
stroke={oc.black}
strokeWidth="2"
/>
<rect
x="2.5"
y="2.5"
width="30"
height="30"
fill={oc.white}
stroke={oc.black}
strokeWidth="6"
/>
<rect
x="2.5"
y="149.5"
width="30"
height="30"
fill={oc.white}
stroke={oc.black}
strokeWidth="6"
/>
<rect
x="147.5"
y="149.5"
width="30"
height="30"
fill={oc.white}
stroke={oc.black}
strokeWidth="6"
/>
<rect
x="147.5"
y="2.5"
width="30"
height="30"
fill={oc.white}
stroke={oc.black}
strokeWidth="6"
/>
</>,
{ width: 182, height: 182 },
export const GroupIcon = React.memo(
({ appearance }: { appearance: "light" | "dark" }) =>
createIcon(
<>
<path d="M25 26H111V111H25" fill={iconFillColor(appearance)} />
<path
d="M25 111C25 80.2068 25 49.4135 25 26M25 26C48.6174 26 72.2348 26 111 26H25ZM25 26C53.3671 26 81.7343 26 111 26H25ZM111 26C111 52.303 111 78.606 111 111V26ZM111 26C111 51.2947 111 76.5893 111 111V26ZM111 111C87.0792 111 63.1585 111 25 111H111ZM111 111C87.4646 111 63.9293 111 25 111H111ZM25 111C25 81.1514 25 51.3028 25 26V111Z"
stroke={iconFillColor(appearance)}
strokeWidth="2"
/>
<path d="M100 100H160V160H100" fill={iconFillColor(appearance)} />
<path
d="M100 160C100 144.106 100 128.211 100 100M100 100C117.706 100 135.412 100 160 100H100ZM100 100C114.214 100 128.428 100 160 100H100ZM160 100C160 120.184 160 140.369 160 160V100ZM160 100C160 113.219 160 126.437 160 160V100ZM160 160C145.534 160 131.068 160 100 160H160ZM160 160C143.467 160 126.934 160 100 160H160ZM100 160C100 143.661 100 127.321 100 100V160Z"
stroke={iconFillColor(appearance)}
strokeWidth="2"
/>
<rect
x="2.5"
y="2.5"
width="30"
height="30"
fill={handlerColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="6"
/>
<rect
x="2.5"
y="149.5"
width="30"
height="30"
fill={handlerColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="6"
/>
<rect
x="147.5"
y="149.5"
width="30"
height="30"
fill={handlerColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="6"
/>
<rect
x="147.5"
y="2.5"
width="30"
height="30"
fill={handlerColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="6"
/>
</>,
{ width: 182, height: 182 },
),
);
export const ungroup = createIcon(
<>
<path d="M25 26H111V111H25" fill={oc.black} />
<path
d="M25 111C25 80.2068 25 49.4135 25 26M25 26C48.6174 26 72.2348 26 111 26H25ZM25 26C53.3671 26 81.7343 26 111 26H25ZM111 26C111 52.303 111 78.606 111 111V26ZM111 26C111 51.2947 111 76.5893 111 111V26ZM111 111C87.0792 111 63.1585 111 25 111H111ZM111 111C87.4646 111 63.9293 111 25 111H111ZM25 111C25 81.1514 25 51.3028 25 26V111Z"
stroke={oc.black}
strokeWidth="2"
/>
<path d="M100 100H160V160H100" fill={oc.black} />
<path
d="M100 160C100 144.106 100 128.211 100 100M100 100C117.706 100 135.412 100 160 100H100ZM100 100C114.214 100 128.428 100 160 100H100ZM160 100C160 120.184 160 140.369 160 160V100ZM160 100C160 113.219 160 126.437 160 160V100ZM160 160C145.534 160 131.068 160 100 160H160ZM160 160C143.467 160 126.934 160 100 160H160ZM100 160C100 143.661 100 127.321 100 100V160Z"
stroke={oc.black}
strokeWidth="2"
/>
<rect
x="2.5"
y="2.5"
width="30"
height="30"
fill={oc.white}
stroke={oc.black}
strokeWidth="6"
/>
<rect
x="78.5"
y="149.5"
width="30"
height="30"
fill={oc.white}
stroke={oc.black}
strokeWidth="6"
/>
<rect
x="147.5"
y="149.5"
width="30"
height="30"
fill={oc.white}
stroke={oc.black}
strokeWidth="6"
/>
<rect
x="147.5"
y="78.5"
width="30"
height="30"
fill={oc.white}
stroke={oc.black}
strokeWidth="6"
/>
<rect
x="105.5"
y="2.5"
width="30"
height="30"
fill={oc.white}
stroke={oc.black}
strokeWidth="6"
/>
<rect
x="2.5"
y="102.5"
width="30"
height="30"
fill={oc.white}
stroke={oc.black}
strokeWidth="6"
/>
</>,
{ width: 182, height: 182 },
export const UngroupIcon = React.memo(
({ appearance }: { appearance: "light" | "dark" }) =>
createIcon(
<>
<path d="M25 26H111V111H25" fill={iconFillColor(appearance)} />
<path
d="M25 111C25 80.2068 25 49.4135 25 26M25 26C48.6174 26 72.2348 26 111 26H25ZM25 26C53.3671 26 81.7343 26 111 26H25ZM111 26C111 52.303 111 78.606 111 111V26ZM111 26C111 51.2947 111 76.5893 111 111V26ZM111 111C87.0792 111 63.1585 111 25 111H111ZM111 111C87.4646 111 63.9293 111 25 111H111ZM25 111C25 81.1514 25 51.3028 25 26V111Z"
stroke={iconFillColor(appearance)}
strokeWidth="2"
/>
<path d="M100 100H160V160H100" fill={iconFillColor(appearance)} />
<path
d="M100 160C100 144.106 100 128.211 100 100M100 100C117.706 100 135.412 100 160 100H100ZM100 100C114.214 100 128.428 100 160 100H100ZM160 100C160 120.184 160 140.369 160 160V100ZM160 100C160 113.219 160 126.437 160 160V100ZM160 160C145.534 160 131.068 160 100 160H160ZM160 160C143.467 160 126.934 160 100 160H160ZM100 160C100 143.661 100 127.321 100 100V160Z"
stroke={iconFillColor(appearance)}
strokeWidth="2"
/>
<rect
x="2.5"
y="2.5"
width="30"
height="30"
fill={handlerColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="6"
/>
<rect
x="78.5"
y="149.5"
width="30"
height="30"
fill={handlerColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="6"
/>
<rect
x="147.5"
y="149.5"
width="30"
height="30"
fill={handlerColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="6"
/>
<rect
x="147.5"
y="78.5"
width="30"
height="30"
fill={handlerColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="6"
/>
<rect
x="105.5"
y="2.5"
width="30"
height="30"
fill={handlerColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="6"
/>
<rect
x="2.5"
y="102.5"
width="30"
height="30"
fill={handlerColor(appearance)}
stroke={iconFillColor(appearance)}
strokeWidth="6"
/>
</>,
{ width: 182, height: 182 },
),
);

View File

@ -1,18 +1,6 @@
@import "./_variables";
@import "./theme";
:root {
--sat: env(safe-area-inset-top);
--sab: env(safe-area-inset-bottom);
--sal: env(safe-area-inset-left);
--sar: env(safe-area-inset-right);
--text-color-primary: #{$oc-gray-8};
--bg-color-main: #{$oc-white};
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
--border-radius-m: 4px;
--space-factor: 0.25rem;
}
body {
margin: 0;
--ui-font: system-ui, BlinkMacSystemFont, -apple-system, Segoe UI, Roboto,
@ -49,6 +37,13 @@ canvas {
image-rendering: pixelated; // chromium
// NOTE: must be declared *after* the above
image-rendering: -moz-crisp-edges; // FF
.Appearance_dark & {
// The percentage is inspired by
// https://material.io/design/color/dark-theme.html#properties, which
// recommends surface color of #121212, 93% yields #111111 for #FFF
filter: var(--appearance-filter);
}
}
.excalidraw {
@ -144,13 +139,13 @@ canvas {
.buttonList label:focus-within,
input:focus {
outline: transparent;
box-shadow: 0 0 0 2px $oc-blue-2;
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
button,
.buttonList label {
user-select: none;
background-color: $oc-gray-2;
background-color: var(--button-gray-1);
border: 0;
border-radius: 4px;
margin: 0.125rem 0;
@ -161,15 +156,15 @@ button,
&:focus {
outline: transparent;
box-shadow: 0 0 0 2px $oc-blue-2;
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
&:hover {
background-color: $oc-gray-4;
background-color: var(--button-gray-2);
}
&:active {
background-color: $oc-gray-5;
background-color: var(--button-gray-3);
}
&:disabled {
@ -179,12 +174,12 @@ button,
.active,
.buttonList label.active {
background-color: $oc-gray-4;
background-color: var(--button-gray-2);
&:hover {
background-color: $oc-gray-4;
background-color: var(--button-gray-2);
}
&:active {
background-color: $oc-gray-5;
background-color: var(--button-gray-3);
}
}
@ -236,6 +231,7 @@ button,
.App-menu {
display: grid;
color: var(--icon-fill-color);
}
.App-menu_top {
@ -267,6 +263,7 @@ button,
cursor: default;
pointer-events: none !important;
left: 0.25rem;
z-index: 100;
&--transition-left {
section {
@ -363,13 +360,14 @@ button,
padding: 0;
padding-inline-start: 0.5rem;
padding-inline-end: 1.5rem;
background-color: $oc-gray-2;
color: var(--icon-fill-color);
background-color: var(--button-gray-1);
border-radius: var(--space-factor);
border: 1px solid $oc-gray-4;
border: 1px solid var(--button-gray-2);
font-size: 0.8rem;
outline: none;
appearance: none;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
background-image: var(--dropdown-icon);
background-repeat: no-repeat;
background-position: right 0.7rem top 50%, 0 0;
:root[dir="rtl"] & {
@ -378,15 +376,15 @@ button,
background-size: 0.65em auto, 100%;
&:focus {
box-shadow: 0 0 0 2px $oc-blue-2;
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
&:hover {
background-color: $oc-gray-4;
background-color: var(--button-gray-2);
}
&:active {
background-color: $oc-gray-4;
background-color: var(--button-gray-2);
}
&.dropdown-select--floating {
position: absolute;
@ -419,6 +417,7 @@ button,
}
.scroll-back-to-content {
color: var(--popup-text-color);
position: fixed;
left: 50%;
bottom: 30px;

View File

@ -1,8 +1,68 @@
@import "open-color/open-color.scss";
:root {
--text-color-primary: #343a40;
--bg-color-main: #fff;
--shadow-island: 0 1px 5px rgba(0, 0, 0, 0.15);
--bg-color-island: rgba(255, 255, 255, 0.9);
--popup-background-color: #{$oc-white};
--border-radius-m: 4px;
--space-factor: 0.25rem;
--button-gray-1: #{$oc-gray-2};
--button-gray-2: #{$oc-gray-4};
--button-gray-3: #{$oc-gray-5};
--input-border-color: #{$oc-gray-3};
--input-background-color: #{$oc-white};
--input-hover-background-color: #{$oc-gray-1};
--input-label-color: #{$oc-gray-7};
--icon-fill-color: #{$oc-black};
--icon-green-fill-color: #{$oc-green-9};
--keybinding-color: #{$oc-gray-5};
--color-overlay-text-color: #ccc;
--sat: env(safe-area-inset-top);
--sab: env(safe-area-inset-bottom);
--sal: env(safe-area-inset-left);
--sar: env(safe-area-inset-right);
--text-color-primary: #{$oc-gray-8};
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
--overlay-background-color: #{transparentize($oc-white, 0.12)};
--border-radius-m: 4px;
--space-factor: 0.25rem;
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
--focus-highlight-color: #{$oc-blue-2};
--select-highlight-color: #{$oc-blue-5};
--appearance-filter: none;
--button-special-active-background-color: #{$oc-green-0};
--button-destructive-color: #{$oc-red-9};
--button-destructive-background-color: #{$oc-red-1};
--popup-secondary-background-color: #{$oc-gray-1};
--popup-text-color: #{$oc-black};
--popup-text-inverted-color: #{$oc-white};
}
.Appearance_dark {
--text-color-primary: #{$oc-gray-4};
--bg-color-island: #1e1e1e;
--popup-background-color: #2c2c2c;
--button-gray-1: #363636;
--button-gray-2: #272727;
--button-gray-3: #222;
--input-border-color: #2e2e2e;
--input-background-color: #121212;
--input-hover-background-color: #181818;
--input-label-color: #{$oc-gray-2};
--icon-fill-color: #{$oc-gray-4};
--icon-green-fill-color: #{$oc-green-4};
--keybinding-color: #{$oc-gray-6};
--color-overlay-text-color: #bbb;
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.7)};
--overlay-background-color: rgba(30, 30, 30, 0.88);
// #{$oc-gray-4}; inlined
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path fill="%23ced4da" d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
--focus-highlight-color: #{$oc-blue-6};
--select-highlight-color: #{$oc-blue-4};
--appearance-filter: invert(93%) hue-rotate(180deg);
--button-special-active-background-color: #204624;
--button-destructive-color: #{$oc-red-3};
--button-destructive-background-color: #5a0000;
--popup-secondary-background-color: #222;
--popup-text-color: #{$oc-gray-4};
--popup-text-inverted-color: #2c2c2c;
}

View File

@ -44,6 +44,7 @@ export const loadFromBlob = async (blob: any, appState?: AppState) => {
elements = data.elements || [];
_appState = {
...defaultAppState,
appearance: _appState.appearance,
...cleanAppStateForExport(data.appState as Partial<AppState>),
...(appState ? calculateScrollCenter(elements, appState, null) : {}),
};

View File

@ -77,6 +77,7 @@ export const textWysiwyg = ({
textAlign: textAlign,
color: updatedElement.strokeColor,
opacity: updatedElement.opacity / 100,
filter: "var(--appearance-filter)",
});
}
}

View File

@ -95,6 +95,7 @@
"roomDialog": "Start live collaboration",
"createNewRoom": "Create new room",
"toggleFullScreen": "Toggle full screen",
"toggleDarkMode": "Toggle dark mode",
"toggleZenMode": "Toggle zen mode",
"exitZenMode": "Exit zen mode"
},

View File

@ -1,5 +1,4 @@
import React from "react";
import oc from "open-color";
// We inline font-awesome icons in order to save on js size rather than including the font awesome react library
export const SHAPES = [
@ -62,7 +61,7 @@ export const SHAPES = [
y1="3"
x2="6"
y2="3"
stroke={oc.black}
stroke="currentColor"
strokeLinecap="round"
/>
</svg>

View File

@ -2,6 +2,7 @@
exports[`regression tests adjusts z order when grouping: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -420,6 +421,7 @@ exports[`regression tests adjusts z order when grouping: [end of test] number of
exports[`regression tests alt-drag duplicates an element: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -640,6 +642,7 @@ exports[`regression tests alt-drag duplicates an element: [end of test] number o
exports[`regression tests arrow keys: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -774,6 +777,7 @@ exports[`regression tests arrow keys: [end of test] number of renders 1`] = `13`
exports[`regression tests change the properties of a shape: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "#fa5252",
"currentItemFillStyle": "hachure",
@ -1048,6 +1052,7 @@ exports[`regression tests change the properties of a shape: [end of test] number
exports[`regression tests click on an element and drag it: [dragged] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -1221,6 +1226,7 @@ exports[`regression tests click on an element and drag it: [dragged] number of r
exports[`regression tests click on an element and drag it: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -1433,6 +1439,7 @@ exports[`regression tests click on an element and drag it: [end of test] number
exports[`regression tests click to select a shape: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -1652,6 +1659,7 @@ exports[`regression tests click to select a shape: [end of test] number of rende
exports[`regression tests click-drag to select a group: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -1976,6 +1984,7 @@ exports[`regression tests click-drag to select a group: [end of test] number of
exports[`regression tests double click to edit a group: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -2389,6 +2398,7 @@ exports[`regression tests double click to edit a group: [end of test] number of
exports[`regression tests draw every type of shape: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -4294,6 +4304,7 @@ exports[`regression tests draw every type of shape: [end of test] number of rend
exports[`regression tests hotkey 2 selects rectangle tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -4428,6 +4439,7 @@ exports[`regression tests hotkey 2 selects rectangle tool: [end of test] number
exports[`regression tests hotkey 3 selects diamond tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -4562,6 +4574,7 @@ exports[`regression tests hotkey 3 selects diamond tool: [end of test] number of
exports[`regression tests hotkey 4 selects ellipse tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -4696,6 +4709,7 @@ exports[`regression tests hotkey 4 selects ellipse tool: [end of test] number of
exports[`regression tests hotkey 5 selects arrow tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -4856,6 +4870,7 @@ exports[`regression tests hotkey 5 selects arrow tool: [end of test] number of r
exports[`regression tests hotkey 6 selects line tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -5016,6 +5031,7 @@ exports[`regression tests hotkey 6 selects line tool: [end of test] number of re
exports[`regression tests hotkey 7 selects draw tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -5176,6 +5192,7 @@ exports[`regression tests hotkey 7 selects draw tool: [end of test] number of re
exports[`regression tests hotkey a selects arrow tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -5336,6 +5353,7 @@ exports[`regression tests hotkey a selects arrow tool: [end of test] number of r
exports[`regression tests hotkey d selects diamond tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -5470,6 +5488,7 @@ exports[`regression tests hotkey d selects diamond tool: [end of test] number of
exports[`regression tests hotkey e selects ellipse tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -5604,6 +5623,7 @@ exports[`regression tests hotkey e selects ellipse tool: [end of test] number of
exports[`regression tests hotkey l selects line tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -5764,6 +5784,7 @@ exports[`regression tests hotkey l selects line tool: [end of test] number of re
exports[`regression tests hotkey r selects rectangle tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -5898,6 +5919,7 @@ exports[`regression tests hotkey r selects rectangle tool: [end of test] number
exports[`regression tests hotkey x selects draw tool: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -6058,6 +6080,7 @@ exports[`regression tests hotkey x selects draw tool: [end of test] number of re
exports[`regression tests keeps selected element selected when click hits element bounding box but doesn't hit the element: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -6195,6 +6218,7 @@ exports[`regression tests keeps selected element selected when click hits elemen
exports[`regression tests make a group and duplicate it: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -6862,6 +6886,7 @@ exports[`regression tests make a group and duplicate it: [end of test] number of
exports[`regression tests noop interaction after undo shouldn't create history entry: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -7082,6 +7107,7 @@ exports[`regression tests noop interaction after undo shouldn't create history e
exports[`regression tests pinch-to-zoom works: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -7155,6 +7181,7 @@ exports[`regression tests pinch-to-zoom works: [end of test] number of renders 1
exports[`regression tests rerenders UI on language change: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -7226,6 +7253,7 @@ exports[`regression tests rerenders UI on language change: [end of test] number
exports[`regression tests resize an element, trying every resize handle: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -8072,6 +8100,7 @@ exports[`regression tests resize an element, trying every resize handle: [end of
exports[`regression tests resize an element, trying every resize handle: [resize handle ne (+5, +5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -8486,6 +8515,7 @@ exports[`regression tests resize an element, trying every resize handle: [resize
exports[`regression tests resize an element, trying every resize handle: [resize handle ne (-5, -5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -8815,6 +8845,7 @@ exports[`regression tests resize an element, trying every resize handle: [resize
exports[`regression tests resize an element, trying every resize handle: [resize handle nw (+5, +5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -9063,6 +9094,7 @@ exports[`regression tests resize an element, trying every resize handle: [resize
exports[`regression tests resize an element, trying every resize handle: [resize handle nw (-5, -5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -9234,6 +9266,7 @@ exports[`regression tests resize an element, trying every resize handle: [resize
exports[`regression tests resize an element, trying every resize handle: [resize handle se (+5, +5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -10028,6 +10061,7 @@ exports[`regression tests resize an element, trying every resize handle: [resize
exports[`regression tests resize an element, trying every resize handle: [resize handle se (-5, -5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -10721,6 +10755,7 @@ exports[`regression tests resize an element, trying every resize handle: [resize
exports[`regression tests resize an element, trying every resize handle: [resize handle sw (+5, +5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -11317,6 +11352,7 @@ exports[`regression tests resize an element, trying every resize handle: [resize
exports[`regression tests resize an element, trying every resize handle: [resize handle sw (-5, -5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -11820,6 +11856,7 @@ exports[`regression tests resize an element, trying every resize handle: [resize
exports[`regression tests resize an element, trying every resize handle: [unresize handle ne (+5, +5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -12278,6 +12315,7 @@ exports[`regression tests resize an element, trying every resize handle: [unresi
exports[`regression tests resize an element, trying every resize handle: [unresize handle ne (-5, -5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -12649,6 +12687,7 @@ exports[`regression tests resize an element, trying every resize handle: [unresi
exports[`regression tests resize an element, trying every resize handle: [unresize handle nw (+5, +5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -12937,6 +12976,7 @@ exports[`regression tests resize an element, trying every resize handle: [unresi
exports[`regression tests resize an element, trying every resize handle: [unresize handle nw (-5, -5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -13146,6 +13186,7 @@ exports[`regression tests resize an element, trying every resize handle: [unresi
exports[`regression tests resize an element, trying every resize handle: [unresize handle se (+5, +5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -13992,6 +14033,7 @@ exports[`regression tests resize an element, trying every resize handle: [unresi
exports[`regression tests resize an element, trying every resize handle: [unresize handle se (-5, -5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -14735,6 +14777,7 @@ exports[`regression tests resize an element, trying every resize handle: [unresi
exports[`regression tests resize an element, trying every resize handle: [unresize handle sw (+5, +5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -15379,6 +15422,7 @@ exports[`regression tests resize an element, trying every resize handle: [unresi
exports[`regression tests resize an element, trying every resize handle: [unresize handle sw (-5, -5)] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -15928,6 +15972,7 @@ exports[`regression tests resize an element, trying every resize handle: [unresi
exports[`regression tests selecting 'Add to library' in context menu adds element to library: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -16062,6 +16107,7 @@ exports[`regression tests selecting 'Add to library' in context menu adds elemen
exports[`regression tests selecting 'Bring forward' in context menu brings element forward: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -16335,6 +16381,7 @@ exports[`regression tests selecting 'Bring forward' in context menu brings eleme
exports[`regression tests selecting 'Bring to front' in context menu brings element to front: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -16608,6 +16655,7 @@ exports[`regression tests selecting 'Bring to front' in context menu brings elem
exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -16742,6 +16790,7 @@ exports[`regression tests selecting 'Copy styles' in context menu copies styles:
exports[`regression tests selecting 'Delete' in context menu deletes element: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -16907,6 +16956,7 @@ exports[`regression tests selecting 'Delete' in context menu deletes element: [e
exports[`regression tests selecting 'Duplicate' in context menu duplicates element: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -17123,6 +17173,7 @@ exports[`regression tests selecting 'Duplicate' in context menu duplicates eleme
exports[`regression tests selecting 'Group selection' in context menu groups selected elements: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -17412,6 +17463,7 @@ exports[`regression tests selecting 'Group selection' in context menu groups sel
exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "#e64980",
"currentItemFillStyle": "cross-hatch",
@ -18198,6 +18250,7 @@ exports[`regression tests selecting 'Paste styles' in context menu pastes styles
exports[`regression tests selecting 'Send backward' in context menu sends element backward: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -18471,6 +18524,7 @@ exports[`regression tests selecting 'Send backward' in context menu sends elemen
exports[`regression tests selecting 'Send to back' in context menu sends element to back: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -18744,6 +18798,7 @@ exports[`regression tests selecting 'Send to back' in context menu sends element
exports[`regression tests selecting 'Ungroup selection' in context menu ungroups selected group: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -19086,6 +19141,7 @@ exports[`regression tests selecting 'Ungroup selection' in context menu ungroups
exports[`regression tests shift-click to multiselect, then drag: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -19372,6 +19428,7 @@ exports[`regression tests shift-click to multiselect, then drag: [end of test] n
exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -19594,6 +19651,7 @@ exports[`regression tests shows 'Group selection' in context menu for multiple s
exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -19886,6 +19944,7 @@ exports[`regression tests shows 'Ungroup selection' in context menu for group in
exports[`regression tests shows context menu for canvas: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -19957,6 +20016,7 @@ exports[`regression tests shows context menu for canvas: [end of test] number of
exports[`regression tests shows context menu for element: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -20091,6 +20151,7 @@ exports[`regression tests shows context menu for element: [end of test] number o
exports[`regression tests spacebar + drag scrolls the canvas: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -20162,6 +20223,7 @@ exports[`regression tests spacebar + drag scrolls the canvas: [end of test] numb
exports[`regression tests supports nested groups: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -20843,6 +20905,7 @@ exports[`regression tests supports nested groups: [end of test] number of render
exports[`regression tests two-finger scroll works: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -20916,6 +20979,7 @@ exports[`regression tests two-finger scroll works: [end of test] number of rende
exports[`regression tests undo/redo drawing an element: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -21368,6 +21432,7 @@ exports[`regression tests undo/redo drawing an element: [end of test] number of
exports[`regression tests updates fontSize & fontFamily appState: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",
@ -21450,6 +21515,7 @@ exports[`regression tests updates fontSize & fontFamily appState: [end of test]
exports[`regression tests zoom hotkeys: [end of test] appState 1`] = `
Object {
"appearance": "light",
"collaborators": Map {},
"currentItemBackgroundColor": "transparent",
"currentItemFillStyle": "hachure",

View File

@ -77,6 +77,7 @@ export type AppState = {
shouldCacheIgnoreZoom: boolean;
showShortcutsDialog: boolean;
zenModeEnabled: boolean;
appearance: "light" | "dark";
gridSize: number | null;
/** top-most selected groups (i.e. does not include nested groups) */