feat: editor redesign 🔥 (#5780)

* Placed eraser into shape switcher (top toolbar).
Redesigned top toolbar.

* Redesigned zoom and undo-redo buttons.

* Started redesigning left toolbar.

* Redesigned help dialog.

* Colour picker now somewhat in line with new design

* [WIP] Changed a bunch of icons.
TODO: organise new icons.

* [WIP] Organised a bunch of icons. Still some to do

* [WIP] Started working on hamburger menu.

* Fixed some bugs with hamburger menu.

* Menu and left toolbar positioning.

* Added some more items to hamburger menu.

* Changed some icons.

* Modal/dialog styling & bunch of fixes.

* Some more dialog improvements & fixes.

* Mobile menu changes.

* Menu can now be closed with outside click.

* Collab avatars and button changes.

* Icon sizing. Left toolbar positioning.

* Implemented welcome screen rendering logic.

* [WIP] Welcome screen content + design.

* Some more welcome screen content and design.

* Merge fixes.

* Tweaked icon set.

* Welcome screen darkmode fix.

* Content updates.

* Various small fixes & adjustments.
Moved language selection into menu.
Fixed some problematic icons.
Slightly moved encryption icon.

* Sidebar header redesign.

* Libraries content rendering logic + some styling.

* Somem more library sidebar styling.

* Publish library dialog styling.

* scroll-back-to-content btn styling

* ColorPicker positioning.

* Library button styling.

* ColorPicker positioning "fix".

* Misc adjustments.

* PenMode button changes.

* Trying to make mobile somewhat usable.

* Added a couple of icons.

* Added some shortcuts.

* Prevent welcome screen flickering.
Fix issue with welcome screen interactivity.
Don't show sidebar button when docked.

* Icon sizing on smaller screens.

* Sidebar styling changes.

* Alignment button... well... alignments.

* Fix inconsistent padding in left toolbar.

* HintViewer changes.

* Hamburger menu changes.

* Move encryption badge back to its original pos.

* Arrowhead changes.
Active state, colours + stronger shadow.

* Added new custom font.

* Fixed bug with library button not rendering.

* Fixed issue with lang selection colours.

* Add tooltips for undo, redo.

* Address some dark mode contrast issues.

* (Re)introduce counter for selectedItems in sidebar

* [WIP] Tweaked bounding box colour & padding.

* Dashed bounding box for remote clients.

* Some more bounding box tweaks.

* Removed docking animation for now...

* Address some RTL issues.

* Welcome screen responsiveness.

* use lighter selection color in dark mode & align naming

* use rounded corners for transform handles

* use lighter gray for welcomeScreen text in dark mode

* disable selection on dialog buttons

* change selection button icon

* fix library item width being flexible

* library: visually align spinner with first section heading

* lint

* fix scrollbar color in dark mode & make thinner

* adapt properties panel max-height

* add shrotcut label to save-to-current-file

* fix unrelated `useOutsideClick` firing for active modal

* add promo color to e+ menu item

* fix type

* lowered button size

* fix transform handles raidus not accounting for zoom

* attempt fix for excal logo on safari

* final fix for excal logo on safari

* fixing fhd resolution button sized

* remove TODO shortcut

* Collab related styling changes.
Expanding avatar list no longer offsets top toolbar.
Added active state & collaborator count badge for collab button.

* Tweaked collab button active colours.

* Added active style to collab btn in hamburger menu

* Remove unnecessary comment.

* Added back promo link for non (signed in) E+ users

* Go to E+ button added for signed in E+ users.

* Close menu & dropdown on modal close.

* tweak icons & fix rendering on smaller sizes [part one]

* align welcomeScreen icons with other UI

* switch icon resize mq to `device-width`

* disable welcomeScreen items `:hover` when selecting on canvas

* change selection box color and style

* reduce selection padding and fix group selection styling

* improve collab cursor styling

- make name borders round
- hide status when "active"
- remove black/gray colors

* add Twitter to hamburger menu

* align collab button

* add shortcut for image export dialog

* revert yarn.lock

* fix more tabler icons

* slightly better-looking penMode button

* change penMode button & tooltip

* revert hamburger menu icon

* align padding on lang picker & canvas bg

* updated robot txt to allow twitter bot and fb bot

* added new OG and tweaked the OG state

* add tooltip to collab button

* align style for scroll-to-content button

* fix pointer-events around toolbar

* fix decor arrow positioning and RTL

* fix welcomeScreen-item active state in dark mode

* change `load` button copy

* prevent shadow anim when opening a docked sidebar

* update E+ links ga params

* show redirect-to-eplus welcomeScreen subheading for signed-in users

* make more generic

* add ga for eplus redirect button

* change copy and icons for hamburger export buttons

* update snaps

* trim the username to account for trailing spaces

* tweaks around decor breakpoints

* fix linear element editor test

* remove .env change

* remove `it.only`

Co-authored-by: dwelle <luzar.david@gmail.com>
Co-authored-by: Maielo <maielo.mv@gmail.com>
Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
This commit is contained in:
Barnabás Molnár 2022-11-01 17:29:58 +01:00 committed by GitHub
parent 4d26993c8f
commit 6334bd832f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
119 changed files with 4963 additions and 3657 deletions

View file

@ -743,8 +743,19 @@ export const renderElement = (
element.x + renderConfig.scrollX,
element.y + renderConfig.scrollY,
);
context.fillStyle = "rgba(0, 0, 255, 0.10)";
context.fillRect(0, 0, element.width, element.height);
context.fillStyle = "rgba(0, 0, 200, 0.04)";
// render from 0.5px offset to get 1px wide line
// https://stackoverflow.com/questions/7530593/html5-canvas-and-line-width/7531540#7531540
// TODO can be be improved by offseting to the negative when user selects
// from right to left
const offset = 0.5 / renderConfig.zoom.value;
context.fillRect(offset, offset, element.width, element.height);
context.lineWidth = 1 / renderConfig.zoom.value;
context.strokeStyle = "rgb(105, 101, 219)";
context.strokeRect(offset, offset, element.width, element.height);
context.restore();
break;
}

View file

@ -62,7 +62,7 @@ import {
import { isLinearElement } from "../element/typeChecks";
const hasEmojiSupport = supportsEmoji();
export const DEFAULT_SPACING = 4;
export const DEFAULT_SPACING = 2;
const strokeRectWithRotation = (
context: CanvasRenderingContext2D,
@ -341,6 +341,8 @@ export const _renderScene = ({
isExporting,
} = renderConfig;
const selectionColor = renderConfig.selectionColor || oc.black;
const context = canvas.getContext("2d")!;
context.setTransform(1, 0, 0, 1, 0, 0);
@ -492,7 +494,7 @@ export const _renderScene = ({
locallySelectedIds.includes(element.id) &&
!isSelectedViaGroup(appState, element)
) {
selectionColors.push(oc.black);
selectionColors.push(selectionColor);
}
// remote users
if (renderConfig.remoteSelectedElementIds[element.id]) {
@ -505,6 +507,7 @@ export const _renderScene = ({
),
);
}
if (selectionColors.length) {
const [elementX1, elementY1, elementX2, elementY2] =
getElementAbsoluteCoords(element);
@ -515,10 +518,11 @@ export const _renderScene = ({
elementX2,
elementY2,
selectionColors,
dashed: !!renderConfig.remoteSelectedElementIds[element.id],
});
}
return acc;
}, [] as { angle: number; elementX1: number; elementY1: number; elementX2: number; elementY2: number; selectionColors: string[] }[]);
}, [] as { angle: number; elementX1: number; elementY1: number; elementX2: number; elementY2: number; selectionColors: string[]; dashed?: boolean }[]);
const addSelectionForGroupId = (groupId: GroupId) => {
const groupElements = getElementsInGroup(elements, groupId);
@ -530,7 +534,8 @@ export const _renderScene = ({
elementX2,
elementY1,
elementY2,
selectionColors: [oc.black],
selectionColors: [selectionColor],
dashed: true,
});
};
@ -542,15 +547,9 @@ export const _renderScene = ({
if (appState.editingGroupId) {
addSelectionForGroupId(appState.editingGroupId);
}
selections.forEach((selection) =>
renderSelectionBorder(
context,
renderConfig,
selection,
isSingleLinearElementSelected
? DEFAULT_SPACING * 2
: DEFAULT_SPACING,
),
renderSelectionBorder(context, renderConfig, selection),
);
}
// Paint resize transformHandles
@ -573,13 +572,15 @@ export const _renderScene = ({
);
}
} else if (locallySelectedElements.length > 1 && !appState.isRotating) {
const dashedLinePadding = 4 / renderConfig.zoom.value;
const dashedLinePadding =
(DEFAULT_SPACING * 2) / renderConfig.zoom.value;
context.fillStyle = oc.white;
const [x1, y1, x2, y2] = getCommonBounds(locallySelectedElements);
const initialLineDash = context.getLineDash();
context.setLineDash([2 / renderConfig.zoom.value]);
const lineWidth = context.lineWidth;
context.lineWidth = 1 / renderConfig.zoom.value;
context.strokeStyle = selectionColor;
strokeRectWithRotation(
context,
x1 - dashedLinePadding,
@ -676,13 +677,11 @@ export const _renderScene = ({
idleState = hasEmojiSupport ? "⚫️" : ` (${UserIdleState.AWAY})`;
} else if (userState === UserIdleState.IDLE) {
idleState = hasEmojiSupport ? "💤" : ` (${UserIdleState.IDLE})`;
} else if (userState === UserIdleState.ACTIVE) {
idleState = hasEmojiSupport ? "🟢" : "";
}
const usernameAndIdleState = `${
username ? `${username} ` : ""
}${idleState}`;
const usernameAndIdleState = `${username || ""}${
idleState ? ` ${idleState}` : ""
}`;
if (!isOutOfBounds && usernameAndIdleState) {
const offsetX = x + width;
@ -693,22 +692,31 @@ export const _renderScene = ({
const measureHeight =
measure.actualBoundingBoxDescent + measure.actualBoundingBoxAscent;
// Border
context.fillStyle = stroke;
context.fillRect(
offsetX - 1,
offsetY - 1,
measure.width + 2 * paddingHorizontal + 2,
measureHeight + 2 * paddingVertical + 2,
);
// Background
context.fillStyle = background;
context.fillRect(
offsetX,
offsetY,
measure.width + 2 * paddingHorizontal,
measureHeight + 2 * paddingVertical,
);
const boxX = offsetX - 1;
const boxY = offsetY - 1;
const boxWidth = measure.width + 2 * paddingHorizontal + 2;
const boxHeight = measureHeight + 2 * paddingVertical + 2;
if (context.roundRect) {
context.beginPath();
context.roundRect(
boxX,
boxY,
boxWidth,
boxHeight,
4 / renderConfig.zoom.value,
);
context.fillStyle = background;
context.fill();
context.fillStyle = stroke;
context.stroke();
} else {
// Border
context.fillStyle = stroke;
context.fillRect(boxX, boxY, boxWidth, boxHeight);
// Background
context.fillStyle = background;
context.fillRect(offsetX, offsetY, boxWidth - 2, boxHeight - 2);
}
context.fillStyle = oc.white;
context.fillText(
@ -807,8 +815,17 @@ const renderTransformHandles = (
context.save();
context.lineWidth = 1 / renderConfig.zoom.value;
if (renderConfig.selectionColor) {
context.strokeStyle = renderConfig.selectionColor;
}
if (key === "rotation") {
fillCircle(context, x + width / 2, y + height / 2, width / 2);
// prefer round corners if roundRect API is available
} else if (context.roundRect) {
context.beginPath();
context.roundRect(x, y, width, height, 2 / renderConfig.zoom.value);
context.fill();
context.stroke();
} else {
strokeRectWithRotation(
context,
@ -837,16 +854,24 @@ const renderSelectionBorder = (
elementX2: number;
elementY2: number;
selectionColors: string[];
dashed?: boolean;
},
padding = 4,
padding = DEFAULT_SPACING * 2,
) => {
const { angle, elementX1, elementY1, elementX2, elementY2, selectionColors } =
elementProperties;
const {
angle,
elementX1,
elementY1,
elementX2,
elementY2,
selectionColors,
dashed,
} = elementProperties;
const elementWidth = elementX2 - elementX1;
const elementHeight = elementY2 - elementY1;
const dashedLinePadding = padding / renderConfig.zoom.value;
const dashWidth = 8 / renderConfig.zoom.value;
const linePadding = padding / renderConfig.zoom.value;
const lineWidth = 8 / renderConfig.zoom.value;
const spaceWidth = 4 / renderConfig.zoom.value;
context.save();
@ -856,17 +881,19 @@ const renderSelectionBorder = (
const count = selectionColors.length;
for (let index = 0; index < count; ++index) {
context.strokeStyle = selectionColors[index];
context.setLineDash([
dashWidth,
spaceWidth + (dashWidth + spaceWidth) * (count - 1),
]);
context.lineDashOffset = (dashWidth + spaceWidth) * index;
if (dashed) {
context.setLineDash([
lineWidth,
spaceWidth + (lineWidth + spaceWidth) * (count - 1),
]);
}
context.lineDashOffset = (lineWidth + spaceWidth) * index;
strokeRectWithRotation(
context,
elementX1 - dashedLinePadding,
elementY1 - dashedLinePadding,
elementWidth + dashedLinePadding * 2,
elementHeight + dashedLinePadding * 2,
elementX1 - linePadding,
elementY1 - linePadding,
elementWidth + linePadding * 2,
elementHeight + linePadding * 2,
elementX1 + elementWidth / 2,
elementY1 + elementHeight / 2,
angle,