feat: redesign toolbar & tweaks (#4387)

This commit is contained in:
David Luzar 2021-12-15 15:31:44 +01:00 committed by GitHub
parent 390da3fd0f
commit 7db63bd397
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 233 additions and 60 deletions

View File

@ -3,15 +3,22 @@ import OpenColor from "open-color";
import "./Card.scss";
export const Card: React.FC<{
color: keyof OpenColor;
color: keyof OpenColor | "primary";
}> = ({ children, color }) => {
return (
<div
className="Card"
style={{
["--card-color" as any]: OpenColor[color][7],
["--card-color-darker" as any]: OpenColor[color][8],
["--card-color-darkest" as any]: OpenColor[color][9],
["--card-color" as any]:
color === "primary" ? "var(--color-primary)" : OpenColor[color][7],
["--card-color-darker" as any]:
color === "primary"
? "var(--color-primary-darker)"
: OpenColor[color][8],
["--card-color-darkest" as any]:
color === "primary"
? "var(--color-primary-darkest)"
: OpenColor[color][9],
}}
>
{children}

View File

@ -22,7 +22,7 @@
align-items: center;
justify-content: center;
&:focus {
&:focus-visible {
outline: transparent;
background-color: var(--button-gray-2);
& svg {

View File

@ -3,7 +3,7 @@
--padding: 0;
background-color: var(--island-bg-color);
box-shadow: var(--shadow-island);
border-radius: 4px;
border-radius: var(--border-radius-lg);
padding: calc(var(--padding) * var(--space-factor));
position: relative;
transition: box-shadow 0.5s ease-in-out;

View File

@ -19,7 +19,6 @@ import { ExportCB, ImageExportDialog } from "./ImageExportDialog";
import { FixedSideContainer } from "./FixedSideContainer";
import { HintViewer } from "./HintViewer";
import { Island } from "./Island";
import "./LayerUI.scss";
import { LoadingMessage } from "./LoadingMessage";
import { LockButton } from "./LockButton";
import { MobileMenu } from "./MobileMenu";
@ -35,6 +34,9 @@ import { LibraryButton } from "./LibraryButton";
import { isImageFileHandle } from "../data/blob";
import { LibraryMenu } from "./LibraryMenu";
import "./LayerUI.scss";
import "./Toolbar.scss";
interface LayerUIProps {
actionManager: ActionManager;
appState: AppState;
@ -305,7 +307,12 @@ const LayerUI = ({
<Section heading="shapes">
{(heading) => (
<Stack.Col gap={4} align="start">
<Stack.Row gap={1}>
<Stack.Row
gap={1}
className={clsx("App-toolbar-container", {
"zen-mode": zenModeEnabled,
})}
>
<LockButton
zenModeEnabled={zenModeEnabled}
checked={appState.elementLocked}
@ -314,7 +321,9 @@ const LayerUI = ({
/>
<Island
padding={1}
className={clsx({ "zen-mode": zenModeEnabled })}
className={clsx("App-toolbar", {
"zen-mode": zenModeEnabled,
})}
>
<HintViewer
appState={appState}

View File

@ -16,18 +16,18 @@ const LIBRARY_ICON = (
export const LibraryButton: React.FC<{
appState: AppState;
setAppState: React.Component<any, AppState>["setState"];
}> = ({ appState, setAppState }) => {
isMobile?: boolean;
}> = ({ appState, setAppState, isMobile }) => {
return (
<label
className={clsx(
"ToolIcon ToolIcon_type_floating ToolIcon__library zen-mode-visibility",
"ToolIcon ToolIcon_type_floating ToolIcon__library",
`ToolIcon_size_medium`,
{
"zen-mode-visibility--hidden": appState.zenModeEnabled,
"is-mobile": isMobile,
},
)}
title={`${capitalizeString(t("toolBar.library"))} — 0`}
style={{ marginInlineStart: "var(--space-factor)" }}
>
<input
className="ToolIcon_type_checkbox"

View File

@ -10,6 +10,7 @@ type LockIconProps = {
checked: boolean;
onChange?(): void;
zenModeEnabled?: boolean;
isMobile?: boolean;
};
const DEFAULT_SIZE: ToolButtonSize = "medium";
@ -42,10 +43,10 @@ export const LockButton = (props: LockIconProps) => {
return (
<label
className={clsx(
"ToolIcon ToolIcon__lock ToolIcon_type_floating zen-mode-visibility",
"ToolIcon ToolIcon__lock ToolIcon_type_floating",
`ToolIcon_size_${DEFAULT_SIZE}`,
{
"zen-mode-visibility--hidden": props.zenModeEnabled,
"is-mobile": props.isMobile,
},
)}
title={`${props.title} — Q`}

View File

@ -64,8 +64,8 @@ export const MobileMenu = ({
<Section heading="shapes">
{(heading) => (
<Stack.Col gap={4} align="center">
<Stack.Row gap={1}>
<Island padding={1}>
<Stack.Row gap={1} className="App-toolbar-container">
<Island padding={1} className="App-toolbar">
{heading}
<Stack.Row gap={1}>
<ShapesSwitcher
@ -85,8 +85,13 @@ export const MobileMenu = ({
checked={appState.elementLocked}
onChange={onLockToggle}
title={t("toolBar.lock")}
isMobile
/>
<LibraryButton
appState={appState}
setAppState={setAppState}
isMobile
/>
<LibraryButton appState={appState} setAppState={setAppState} />
</Stack.Row>
{libraryMenu}
</Stack.Col>

View File

@ -8,17 +8,7 @@
position: relative;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
border-radius: var(--space-factor);
user-select: none;
background-color: var(--button-gray-1);
&:hover {
background-color: var(--button-gray-2);
}
&:active {
background-color: var(--button-gray-3);
}
}
.ToolIcon--plain {
@ -29,6 +19,20 @@
}
}
.ToolIcon_type_radio,
.ToolIcon_type_checkbox {
& + .ToolIcon__icon {
background-color: var(--button-gray-1);
&:hover {
background-color: var(--button-gray-2);
}
&:active {
background-color: var(--button-gray-3);
}
}
}
.ToolIcon__icon {
width: 2.5rem;
height: 2.5rem;
@ -38,7 +42,11 @@
justify-content: center;
align-items: center;
border-radius: var(--space-factor);
border-radius: var(--border-radius-lg);
& + .ToolIcon__label {
margin-inline-start: 0;
}
svg {
position: relative;
@ -46,10 +54,6 @@
fill: var(--icon-fill-color);
color: var(--icon-fill-color);
}
& + .ToolIcon__label {
margin-inline-start: 0;
}
}
.ToolIcon__label {
@ -79,7 +83,7 @@
margin: 0;
font-size: inherit;
&:focus {
&:focus-visible {
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
@ -121,7 +125,7 @@
}
}
&:focus + .ToolIcon__icon {
&:focus-visible + .ToolIcon__icon {
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
@ -141,10 +145,6 @@
background-color: transparent;
}
&:focus {
box-shadow: none;
}
.ToolIcon__icon {
background-color: var(--button-gray-1);
&:hover {
@ -159,13 +159,6 @@
}
}
.ToolIcon.ToolIcon__lock {
margin-inline-end: var(--space-factor);
&.ToolIcon_type_floating {
margin-left: 0.1rem;
}
}
.ToolIcon__keybinding {
position: absolute;
bottom: 2px;

112
src/components/Toolbar.scss Normal file
View File

@ -0,0 +1,112 @@
@import "open-color/open-color.scss";
@mixin toolbarButtonColorStates {
.ToolIcon_type_radio,
.ToolIcon_type_checkbox {
& + .ToolIcon__icon:active {
background: var(--color-primary-light);
}
&:checked + .ToolIcon__icon {
background: var(--color-primary);
--icon-fill-color: #{$oc-white};
--keybinding-color: #{$oc-white};
}
&:checked + .ToolIcon__icon:active {
background: var(--color-primary-darker);
}
}
.ToolIcon__keybinding {
bottom: 4px;
right: 4px;
}
}
.excalidraw {
.App-toolbar-container {
.ToolIcon_type_floating {
@include toolbarButtonColorStates;
&:not(.is-mobile) {
.ToolIcon__icon {
padding: 1px;
background-color: var(--island-bg-color);
box-shadow: 1px 3px 4px 0px rgb(0 0 0 / 15%);
border-radius: 50%;
transition: box-shadow 0.5s ease, transform 0.5s ease;
}
}
.ToolIcon_type_radio,
.ToolIcon_type_checkbox {
&:focus-within + .ToolIcon__icon {
// override for custom floating button shadow
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
}
}
.ToolIcon.ToolIcon__lock {
margin-inline-end: var(--space-factor);
&.ToolIcon_type_floating {
margin-left: 0.1rem;
}
}
.ToolIcon__library {
margin-inline-start: var(--space-factor);
}
&.zen-mode {
.ToolIcon_type_floating {
.ToolIcon__icon {
box-shadow: none;
transform: scale(0.9);
}
.ToolIcon_type_checkbox:not(:checked):not(:hover):not(:active) {
& + .ToolIcon__icon {
svg {
fill: $oc-gray-5;
color: $oc-gray-5;
}
}
}
}
}
}
.App-toolbar {
border-radius: var(--border-radius-lg);
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.01), 1px 1px 5px rgb(0 0 0 / 15%);
.ToolIcon {
&:hover {
--icon-fill-color: var(--color-primary-chubb);
--keybinding-color: var(--color-primary-chubb);
}
&:active {
--icon-fill-color: #{$oc-gray-9};
--keybinding-color: #{$oc-gray-9};
}
.ToolIcon__icon {
background: transparent;
border-radius: var(--border-radius-lg);
}
@include toolbarButtonColorStates;
}
&.zen-mode {
.ToolIcon__keybinding,
.HintViewer {
display: none;
}
}
}
&.theme--dark .App-toolbar .ToolIcon:active {
--icon-fill-color: #{$oc-gray-3};
--keybinding-color: #{$oc-gray-3};
}
}

View File

@ -15,8 +15,9 @@ import { THEME } from "../constants";
const activeElementColor = (theme: Theme) =>
theme === THEME.LIGHT ? oc.orange[4] : oc.orange[9];
const iconFillColor = (theme: Theme) =>
theme === THEME.LIGHT ? oc.black : oc.gray[4];
const iconFillColor = (theme: Theme) => "var(--icon-fill-color)";
const handlerColor = (theme: Theme) =>
theme === THEME.LIGHT ? oc.white : "#1e1e1e";

View File

@ -180,7 +180,7 @@
}
.buttonList label:focus-within,
input:focus {
input:focus-visible {
outline: transparent;
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
@ -190,14 +190,14 @@
user-select: none;
background-color: var(--button-gray-1);
border: 0;
border-radius: 4px;
border-radius: var(--border-radius-md);
margin: 0.125rem 0;
padding: 0.25rem;
white-space: nowrap;
cursor: pointer;
&:focus {
&:focus-visible {
outline: transparent;
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
@ -217,14 +217,16 @@
.active,
.buttonList label.active {
background-color: var(--button-gray-2);
background-color: var(--color-primary);
--icon-fill-color: #{$oc-white};
&:hover {
background-color: var(--button-gray-2);
background-color: var(--color-primary-darker);
}
&:active {
background-color: var(--button-gray-3);
background-color: var(--color-primary-darkest);
}
}
@ -234,7 +236,7 @@
justify-content: center;
align-items: center;
svg {
width: 36px;
width: 35px;
height: 14px;
padding: 2px;
opacity: 0.6;

View File

@ -12,7 +12,7 @@
--dialog-border-color: #{$oc-gray-6};
--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};
--icon-fill-color: #{$oc-black};
--icon-fill-color: #{$oc-gray-9};
--icon-green-fill-color: #{$oc-green-9};
--default-bg-color: #{$oc-white};
--input-bg-color: #{$oc-white};
@ -32,10 +32,20 @@
--sar: env(safe-area-inset-right);
--sat: env(safe-area-inset-top);
--select-highlight-color: #{$oc-blue-5};
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
--shadow-island: 0 0 0 1px rgba(0, 0, 0, 0.01), 1px 1px 5px rgb(0 0 0 / 12%);
--space-factor: 0.25rem;
--text-primary-color: #{$oc-gray-8};
--color-primary: #6965db;
--color-primary-chubb: #625ee0; // to offset Chubb illusion
--color-primary-darker: #5b57d1;
--color-primary-darkest: #4a47b1;
--color-primary-light: #e2e1fc;
--border-radius-md: 0.375rem;
--border-radius-lg: 0.5rem;
&.theme--dark {
background: $oc-black;
@ -71,7 +81,13 @@
--popup-text-color: #{$oc-gray-4};
--popup-text-inverted-color: #2c2c2c;
--select-highlight-color: #{$oc-blue-4};
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.7)};
--shadow-island: 1px 1px 5px #{transparentize($oc-black, 0.7)};
--text-primary-color: #{$oc-gray-4};
--color-primary: #5650f0;
--color-primary-chubb: #726dff; // to offset Chubb illusion
--color-primary-darker: #4b46d8;
--color-primary-darkest: #3e39be;
--color-primary-light: #3f3d64;
}
}

View File

@ -78,7 +78,7 @@ export const ExportToExcalidrawPlus: React.FC<{
onError: (error: Error) => void;
}> = ({ elements, appState, files, onError }) => {
return (
<Card color="indigo">
<Card color="primary">
<div className="Card-icon">{excalidrawPlusIcon}</div>
<h2>Excalidraw+</h2>
<div className="Card-details">

View File

@ -9,7 +9,7 @@
.encrypted-icon {
border-radius: var(--space-factor);
color: var(--icon-green-fill-color);
color: var(--color-primary);
margin-top: auto;
margin-bottom: auto;
margin-inline-start: auto;

View File

@ -19,6 +19,8 @@ Please add the latest change on the top under the correct section.
### Features
- Introduced primary colors to the app. The colors can be overriden. Check [readme](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#customizing-styles) on how to do so.
- #### BREAKING CHANGE
Removed `getElementMap` util method.

View File

@ -353,6 +353,31 @@ To view the full example visit :point_down:
</details>
### Customizing styles
Excalidraw is using CSS variables to style certain components. To override them, you should set your own on the `.excalidraw` and `.excalidraw.theme--dark` (for dark mode variables) selectors.
Make sure the selector has higher specificity, e.g. by prefixing it with your app's selector:
```css
.your-app .excalidraw {
--color-primary: red;
}
.your-app .excalidraw.theme--dark {
--color-primary: pink;
}
```
Most notably, you can customize the primary colors, by overriding these variables:
- `--color-primary`
- `--color-primary-darker`
- `--color-primary-darkest`
- `--color-primary-light`
- `--color-primary-chubb` — a slightly darker (in light mode), or lighter (in dark mode) `--color-primary` color to account for [Chubb illusion](https://en.wikipedia.org/wiki/Chubb_illusion).
For a complete list of variables, check [theme.scss](https://github.com/excalidraw/excalidraw/blob/master/src/css/theme.scss), though most of them will not make sense to override.
### Props
| Name | Type | Default | Description |