feat: zigzag fill easter egg (#6439)

This commit is contained in:
David Luzar 2023-04-10 15:38:50 +02:00 committed by GitHub
parent ec215362a1
commit e4d8ba226f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 120 additions and 62 deletions

View File

@ -1,4 +1,5 @@
import { AppState } from "../../src/types"; import { AppState } from "../../src/types";
import { trackEvent } from "../analytics";
import { ButtonIconSelect } from "../components/ButtonIconSelect"; import { ButtonIconSelect } from "../components/ButtonIconSelect";
import { ColorPicker } from "../components/ColorPicker"; import { ColorPicker } from "../components/ColorPicker";
import { IconPicker } from "../components/IconPicker"; import { IconPicker } from "../components/IconPicker";
@ -37,6 +38,7 @@ import {
TextAlignLeftIcon, TextAlignLeftIcon,
TextAlignCenterIcon, TextAlignCenterIcon,
TextAlignRightIcon, TextAlignRightIcon,
FillZigZagIcon,
} from "../components/icons"; } from "../components/icons";
import { import {
DEFAULT_FONT_FAMILY, DEFAULT_FONT_FAMILY,
@ -294,7 +296,12 @@ export const actionChangeBackgroundColor = register({
export const actionChangeFillStyle = register({ export const actionChangeFillStyle = register({
name: "changeFillStyle", name: "changeFillStyle",
trackEvent: false, trackEvent: false,
perform: (elements, appState, value) => { perform: (elements, appState, value, app) => {
trackEvent(
"element",
"changeFillStyle",
`${value} (${app.device.isMobile ? "mobile" : "desktop"})`,
);
return { return {
elements: changeProperty(elements, appState, (el) => elements: changeProperty(elements, appState, (el) =>
newElementWith(el, { newElementWith(el, {
@ -305,15 +312,23 @@ export const actionChangeFillStyle = register({
commitToHistory: true, commitToHistory: true,
}; };
}, },
PanelComponent: ({ elements, appState, updateData }) => ( PanelComponent: ({ elements, appState, updateData }) => {
const selectedElements = getSelectedElements(elements, appState);
const allElementsZigZag = selectedElements.every(
(el) => el.fillStyle === "zigzag",
);
return (
<fieldset> <fieldset>
<legend>{t("labels.fill")}</legend> <legend>{t("labels.fill")}</legend>
<ButtonIconSelect <ButtonIconSelect
type="button"
options={[ options={[
{ {
value: "hachure", value: "hachure",
text: t("labels.hachure"), text: t("labels.hachure"),
icon: FillHachureIcon, icon: allElementsZigZag ? FillZigZagIcon : FillHachureIcon,
active: allElementsZigZag ? true : undefined,
}, },
{ {
value: "cross-hatch", value: "cross-hatch",
@ -326,19 +341,26 @@ export const actionChangeFillStyle = register({
icon: FillSolidIcon, icon: FillSolidIcon,
}, },
]} ]}
group="fill"
value={getFormValue( value={getFormValue(
elements, elements,
appState, appState,
(element) => element.fillStyle, (element) => element.fillStyle,
appState.currentItemFillStyle, appState.currentItemFillStyle,
)} )}
onChange={(value) => { onClick={(value, event) => {
updateData(value); const nextValue =
event.altKey &&
value === "hachure" &&
selectedElements.every((el) => el.fillStyle === "hachure")
? "zigzag"
: value;
updateData(nextValue);
}} }}
/> />
</fieldset> </fieldset>
), );
},
}); });
export const actionChangeStrokeWidth = register({ export const actionChangeStrokeWidth = register({

View File

@ -1,33 +1,59 @@
import clsx from "clsx"; import clsx from "clsx";
// TODO: It might be "clever" to add option.icon to the existing component <ButtonSelect /> // TODO: It might be "clever" to add option.icon to the existing component <ButtonSelect />
export const ButtonIconSelect = <T extends Object>({ export const ButtonIconSelect = <T extends Object>(
options, props: {
value, options: {
onChange, value: T;
group, text: string;
}: { icon: JSX.Element;
options: { value: T; text: string; icon: JSX.Element; testId?: string }[]; testId?: string;
/** if not supplied, defaults to value identity check */
active?: boolean;
}[];
value: T | null; value: T | null;
onChange: (value: T) => void; type?: "radio" | "button";
group: string; } & (
}) => ( | { type?: "radio"; group: string; onChange: (value: T) => void }
| {
type: "button";
onClick: (
value: T,
event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
) => void;
}
),
) => (
<div className="buttonList buttonListIcon"> <div className="buttonList buttonListIcon">
{options.map((option) => ( {props.options.map((option) =>
props.type === "button" ? (
<button
key={option.text}
onClick={(event) => props.onClick(option.value, event)}
className={clsx({
active: option.active ?? props.value === option.value,
})}
data-testid={option.testId}
title={option.text}
>
{option.icon}
</button>
) : (
<label <label
key={option.text} key={option.text}
className={clsx({ active: value === option.value })} className={clsx({ active: props.value === option.value })}
title={option.text} title={option.text}
> >
<input <input
type="radio" type="radio"
name={group} name={props.group}
onChange={() => onChange(option.value)} onChange={() => props.onChange(option.value)}
checked={value === option.value} checked={props.value === option.value}
data-testid={option.testId} data-testid={option.testId}
/> />
{option.icon} {option.icon}
</label> </label>
))} ),
)}
</div> </div>
); );

View File

@ -1008,6 +1008,13 @@ export const UngroupIcon = React.memo(({ theme }: { theme: Theme }) =>
), ),
); );
export const FillZigZagIcon = createIcon(
<g strokeWidth={1.25}>
<path d="M5.879 2.625h8.242a3.27 3.27 0 0 1 3.254 3.254v8.242a3.27 3.27 0 0 1-3.254 3.254H5.88a3.27 3.27 0 0 1-3.254-3.254V5.88A3.27 3.27 0 0 1 5.88 2.626l-.001-.001ZM4.518 16.118l7.608-12.83m.198 13.934 5.051-9.897M2.778 9.675l9.348-6.387m-7.608 12.83 12.857-8.793" />
</g>,
modifiedTablerIconProps,
);
export const FillHachureIcon = createIcon( export const FillHachureIcon = createIcon(
<> <>
<path <path

View File

@ -155,6 +155,9 @@
margin: 1px; margin: 1px;
} }
.welcome-screen-menu-item:focus-visible,
.dropdown-menu-item:focus-visible,
button:focus-visible,
.buttonList label:focus-within, .buttonList label:focus-within,
input:focus-visible { input:focus-visible {
outline: transparent; outline: transparent;

View File

@ -9,7 +9,7 @@ import {
import { MarkNonNullable, ValueOf } from "../utility-types"; import { MarkNonNullable, ValueOf } from "../utility-types";
export type ChartType = "bar" | "line"; export type ChartType = "bar" | "line";
export type FillStyle = "hachure" | "cross-hatch" | "solid"; export type FillStyle = "hachure" | "cross-hatch" | "solid" | "zigzag";
export type FontFamilyKeys = keyof typeof FONT_FAMILY; export type FontFamilyKeys = keyof typeof FONT_FAMILY;
export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys]; export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys];
export type Theme = typeof THEME[keyof typeof THEME]; export type Theme = typeof THEME[keyof typeof THEME];