From e4d8ba226f15836b4572fc3bae6a623e809cf08c Mon Sep 17 00:00:00 2001 From: David Luzar Date: Mon, 10 Apr 2023 15:38:50 +0200 Subject: [PATCH] feat: zigzag fill easter egg (#6439) --- src/actions/actionProperties.tsx | 92 ++++++++++++++++++----------- src/components/ButtonIconSelect.tsx | 78 ++++++++++++++++-------- src/components/icons.tsx | 7 +++ src/css/styles.scss | 3 + src/element/types.ts | 2 +- 5 files changed, 120 insertions(+), 62 deletions(-) diff --git a/src/actions/actionProperties.tsx b/src/actions/actionProperties.tsx index 08420d9e..ed714816 100644 --- a/src/actions/actionProperties.tsx +++ b/src/actions/actionProperties.tsx @@ -1,4 +1,5 @@ import { AppState } from "../../src/types"; +import { trackEvent } from "../analytics"; import { ButtonIconSelect } from "../components/ButtonIconSelect"; import { ColorPicker } from "../components/ColorPicker"; import { IconPicker } from "../components/IconPicker"; @@ -37,6 +38,7 @@ import { TextAlignLeftIcon, TextAlignCenterIcon, TextAlignRightIcon, + FillZigZagIcon, } from "../components/icons"; import { DEFAULT_FONT_FAMILY, @@ -294,7 +296,12 @@ export const actionChangeBackgroundColor = register({ export const actionChangeFillStyle = register({ name: "changeFillStyle", trackEvent: false, - perform: (elements, appState, value) => { + perform: (elements, appState, value, app) => { + trackEvent( + "element", + "changeFillStyle", + `${value} (${app.device.isMobile ? "mobile" : "desktop"})`, + ); return { elements: changeProperty(elements, appState, (el) => newElementWith(el, { @@ -305,40 +312,55 @@ export const actionChangeFillStyle = register({ commitToHistory: true, }; }, - PanelComponent: ({ elements, appState, updateData }) => ( -
- {t("labels.fill")} - element.fillStyle, - appState.currentItemFillStyle, - )} - onChange={(value) => { - updateData(value); - }} - /> -
- ), + PanelComponent: ({ elements, appState, updateData }) => { + const selectedElements = getSelectedElements(elements, appState); + const allElementsZigZag = selectedElements.every( + (el) => el.fillStyle === "zigzag", + ); + + return ( +
+ {t("labels.fill")} + element.fillStyle, + appState.currentItemFillStyle, + )} + onClick={(value, event) => { + const nextValue = + event.altKey && + value === "hachure" && + selectedElements.every((el) => el.fillStyle === "hachure") + ? "zigzag" + : value; + + updateData(nextValue); + }} + /> +
+ ); + }, }); export const actionChangeStrokeWidth = register({ diff --git a/src/components/ButtonIconSelect.tsx b/src/components/ButtonIconSelect.tsx index 899ec150..eec8870a 100644 --- a/src/components/ButtonIconSelect.tsx +++ b/src/components/ButtonIconSelect.tsx @@ -1,33 +1,59 @@ import clsx from "clsx"; // TODO: It might be "clever" to add option.icon to the existing component -export const ButtonIconSelect = ({ - options, - value, - onChange, - group, -}: { - options: { value: T; text: string; icon: JSX.Element; testId?: string }[]; - value: T | null; - onChange: (value: T) => void; - group: string; -}) => ( +export const ButtonIconSelect = ( + props: { + options: { + value: T; + text: string; + icon: JSX.Element; + testId?: string; + /** if not supplied, defaults to value identity check */ + active?: boolean; + }[]; + value: T | null; + type?: "radio" | "button"; + } & ( + | { type?: "radio"; group: string; onChange: (value: T) => void } + | { + type: "button"; + onClick: ( + value: T, + event: React.MouseEvent, + ) => void; + } + ), +) => (
- {options.map((option) => ( -
); diff --git a/src/components/icons.tsx b/src/components/icons.tsx index 046ee490..784e8102 100644 --- a/src/components/icons.tsx +++ b/src/components/icons.tsx @@ -1008,6 +1008,13 @@ export const UngroupIcon = React.memo(({ theme }: { theme: Theme }) => ), ); +export const FillZigZagIcon = createIcon( + + + , + modifiedTablerIconProps, +); + export const FillHachureIcon = createIcon( <>