Skip to content

Commit

Permalink
Caching pass
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-rogerson committed Dec 16, 2023
1 parent d0eb122 commit 28e723b
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 90 deletions.
6 changes: 3 additions & 3 deletions src/components/Detail.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { forwardRef, useEffect, useRef, useState } from "react";
import { forwardRef, memo, useEffect, useRef, useState } from "react";
import { Sortable } from "@/components/Sortable";
import {
bugIcon,
Expand Down Expand Up @@ -65,7 +65,7 @@ function ExampleItem(props: ExampleItem) {
);
}

export const AddEditor = (props: { editorId: string }) => {
export const AddEditor = memo(function AddEditor(props: { editorId: string }) {
const { updateEditorSvg, addEditor } = useAppActions();

const ref = useRef<HTMLInputElement>(null);
Expand Down Expand Up @@ -108,7 +108,7 @@ export const AddEditor = (props: { editorId: string }) => {
</div>
</div>
);
};
});

const ConfigPanelNoSSR = dynamic(
() =>
Expand Down
7 changes: 2 additions & 5 deletions src/components/GroupSet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,7 @@ const Guides = () => {
// );
// };

const relativeTime = (date: number) => {
const timeString = intlFormatDistance(date, new Date());
return timeString;
};
const relativeTime = (date: number) => intlFormatDistance(date, new Date());

const Header: FunctionComponent<{
id: string;
Expand All @@ -135,7 +132,7 @@ const Header: FunctionComponent<{
<input
type="text"
value={title}
placeholder={props.title ? "" : "Untitled set…"}
placeholder={title ? "" : "Untitled set…"}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
props.updateGroupTitle(props.id, e.currentTarget.value);
setTitle(e.currentTarget.value);
Expand Down
19 changes: 5 additions & 14 deletions src/components/Sortable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useId, useState } from "react";
import { memo, useCallback, useEffect, useId, useState } from "react";
import {
closestCenter,
DndContext,
Expand All @@ -16,11 +16,11 @@ import { Editor } from "@/feature/editor/components/Editor";
import { useAppActions, useAppStore } from "@/hooks/appState";
import { cn, tw } from "@/lib/utils";

const Add = (props: {
const Add = memo(function Memo(props: {
onClick: () => void;
isTop?: boolean;
isVisible?: boolean;
}) => {
}) {
const isVisible = props.isVisible ?? false;
return (
<button
Expand All @@ -42,7 +42,7 @@ const Add = (props: {
</div>
</button>
);
};
});

/**
* Update the group list when the hash changes.
Expand All @@ -64,16 +64,7 @@ const Sortable = () => {
const { addEditorAtIndex, updateOrder } = useAppActions();

const id = useId();
const sensors = useSensors(
// touchSensor,
useSensor(MouseSensor)
// useSensor(PointerSensor),
// useSensor(KeyboardSensor, {
// coordinateGetter: sortableKeyboardCoordinates,
// })
);

// console.log({ sortable: "rerender" });
const sensors = useSensors(useSensor(MouseSensor));

const getEditors = useEditorsRender();

Expand Down
35 changes: 33 additions & 2 deletions src/feature/config/components/ConfigPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,14 @@ type ConfigSelect = {
onChange: (val: string) => void;
};

type ConfigType = ConfigRange | ConfigInput | ConfigSelect;
type ConfigCheckbox = {
title: string;
defaultChecked: boolean;
type: "checkbox";
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
};

type ConfigType = ConfigRange | ConfigInput | ConfigSelect | ConfigCheckbox;

const isRange = (item: ConfigType): item is ConfigRange =>
"type" in item && item.type === "range";
Expand All @@ -71,6 +78,9 @@ const isInput = (item: ConfigType): item is ConfigInput =>

const isSelect = (item: ConfigType): item is ConfigSelect => !("type" in item);

const isCheckbox = (item: ConfigType): item is ConfigCheckbox =>
"type" in item && item.type === "checkbox";

export const ConfigPanel = () => {
const activeGroupId = useAppStore((s) => s.activeGroupId);
const { getConfig, setConfig } = useAppActions();
Expand All @@ -82,7 +92,7 @@ export const ConfigPanel = () => {
title: "stroke width",
defaultValue: config.strokeWidth,
type: "range",
onChange: (val: number[]) => {
onChange: (val) => {
setConfig({ strokeWidth: String(val[0]) });
},
} satisfies ConfigRange,
Expand Down Expand Up @@ -143,6 +153,14 @@ export const ConfigPanel = () => {
setConfig({ strokeLinejoin });
},
} satisfies ConfigSelect,
{
title: "non-scaling-stroke",
defaultChecked: config.nonScalingStroke,
type: "checkbox",
onChange: (e) => {
setConfig({ nonScalingStroke: Boolean(e.target.value) });
},
} satisfies ConfigCheckbox,
],
[setConfig, config]
);
Expand Down Expand Up @@ -256,6 +274,19 @@ export const ConfigPanel = () => {
</div>
</div>
);

if (isCheckbox(item))
return (
<>
<label htmlFor={`checkbox-${i}`}>{item.title}</label>
<input
type={item.type}
defaultChecked={item.defaultValue}
onChange={item.onChange}
onBlur={item.onBlur}
/>
</>
);
})}
</Fragment>
))}
Expand Down
1 change: 1 addition & 0 deletions src/feature/config/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const configSchema = z.object({
fill: z.string(),
strokeLinecap: z.string(),
strokeLinejoin: z.string(),
nonScalingStroke: z.boolean(),
});

export { configSchema };
38 changes: 21 additions & 17 deletions src/feature/editor/components/Alerts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { memo } from "react";

const warningIcon = (
<svg
Expand Down Expand Up @@ -94,25 +95,28 @@ const alerts = new Map([
export const parseSvgClient = (svg: string) =>
new DOMParser().parseFromString(svg, "image/svg+xml");

export const Alerts = (props: { svg: string }) => {
const svg = parseSvgClient(props.svg);
const alertDisplay = (svg: Document) =>
[...alerts]
.map(([title, { desc, fix, test }]) => {
if (!test(svg)) return null;

const alertsList = [...alerts].map(([title, { desc, fix, test }]) => {
if (!test(svg)) return null;

return (
<div className="flex gap-3.5" key={title}>
<div className="text-2xl">{warningIcon}</div>
<div className="grid gap-y-1">
<h2 className="font-bold">{title}</h2>
<div>{desc}</div>
<div>Fix: {fix}</div>
return (
<div className="flex gap-3.5" key={title}>
<div className="text-2xl">{warningIcon}</div>
<div className="grid gap-y-1">
<h2 className="font-bold">{title}</h2>
<div>{desc}</div>
<div>Fix: {fix}</div>
</div>
</div>
</div>
);
});
);
})
.filter(Boolean);

export const Alerts = memo(function Alerts(props: { svg: string }) {
const alertsList = alertDisplay(parseSvgClient(props.svg));

if (alertsList.filter(Boolean).length === 0) return null;
if (alertsList.length === 0) return null;

return (
<div className="absolute bottom-2 left-2">
Expand All @@ -128,4 +132,4 @@ export const Alerts = (props: { svg: string }) => {
</TooltipProvider>
</div>
);
};
});
35 changes: 16 additions & 19 deletions src/feature/editor/components/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { javascript } from "@codemirror/lang-javascript";
import { EditorView } from "@codemirror/view";
import { vscodeDark } from "@uiw/codemirror-theme-vscode";
import CodeMirror from "@uiw/react-codemirror";
import { useMemo } from "react";
import { useCopyToClipboard } from "usehooks-ts";

type EditorProps = {
Expand All @@ -22,30 +23,26 @@ type EditorProps = {

const Editor = (props: EditorProps) => {
const { removeEditor, updateEditorSvg } = useAppActions();
const sanitizedSvg = doSanitizeSvg(props.data.view?.doc ?? "");
const [hasWordWrapIn, WordWrapIn] = useEditorWrap(false);
const [hasWordWrapOut, WordWrapOut] = useEditorWrap(true);
const [copied, copy] = useCopyToClipboard();
const sanitizedSvg = useMemo(
() => doSanitizeSvg(props.data.view?.doc ?? ""),
[props.data.view?.doc]
);
const sized = useMemo(
() =>
calculateSizeSavings(props.data.view?.doc ?? "", props.data.svg.output),
[props.data.view?.doc, props.data.svg.output]
);

const svg = props.data.svg;
const showOutput = svg.output !== "" && svg.output.includes("<svg");
const sized = calculateSizeSavings(props.data.view?.doc ?? "", svg.output);
const showOutput =
props.data.svg.output !== "" && props.data.svg.output.includes("<svg");

const handleOnChange = (value: string) => {
updateEditorSvg(props.id, value);
};

// updateEditor([props.id, { svg }]);
// console.log({ TODO: "save on update perhaps?" });
// };
// const handleOnUpdateOut = (viewUpdate: ViewUpdate) => {
// const view = viewUpdate.state.toJSON({
// history: historyField,
// }) as View;
// updateEditor([props.id, { svg }]);
// console.log({ TODO: "save on update perhaps?" });
// };

return (
<div className="group/editor relative grid gap-3">
<div className="grid grid-cols-2">
Expand Down Expand Up @@ -100,13 +97,13 @@ const Editor = (props: EditorProps) => {
{Boolean(showOutput) && (
<div className="grid-cols-[minmax(0,_0.25fr)_minmax(0,_1fr)] md:grid">
<div className="relative rounded-l border border-[--line-border] bg-[--page-bg-dark] p-[25%]">
<div dangerouslySetInnerHTML={{ __html: svg.output }} />
<div dangerouslySetInnerHTML={{ __html: props.data.svg.output }} />
<div className="absolute left-2 top-2 hidden text-xs text-[--text-muted] group-focus-within/editor:block group-hover/editor:block">
{sized.after}
</div>
</div>
<div className="relative rounded-r border border-l-0 border-[--line-border] p-6">
{svg.output.length > 30 && (
{props.data.svg.output.length > 30 && (
<div className="absolute right-6 top-0 -mt-2.5 flex justify-end bg-[--page-bg] px-1.5 group-focus-within/editor:block group-hover/editor:block md:hidden">
<WordWrapOut />
</div>
Expand All @@ -118,14 +115,14 @@ const Editor = (props: EditorProps) => {
[...[hasWordWrapOut ? EditorView.lineWrapping : []]],
]}
theme={vscodeDark}
value={svg.output}
value={props.data.svg.output}
// onUpdate={handleOnUpdateOut}
/>
<div className="text-md absolute -bottom-3 left-0 flex w-full justify-between px-6 uppercase">
<div className="flex gap-3">
<Button
onClick={() => {
copy(svg.output).catch(() => null);
copy(props.data.svg.output).catch(() => null);
}}
>
<span className="uppercase text-[--text-muted]">
Expand Down
67 changes: 37 additions & 30 deletions src/feature/editor/editor.hooks.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from "react";
import { memo, useState } from "react";

export const useEditor = (initialValue?: string) => {
const [value, setValue] = useState(initialValue ?? "");
Expand All @@ -10,41 +10,48 @@ export const useEditor = (initialValue?: string) => {
return { onChange, value };
};

const Wrap = memo(function Wrap(props: {
wordWrap: boolean;
setWordWrap: (checked: boolean) => void;
}) {
return (
<label className="text-base flex items-center gap-2 text-[--text-muted] hover:text-[--text] cursor-pointer select-none">
<input
checked={props.wordWrap}
className="hidden"
onChange={(e) => {
props.setWordWrap(e.target.checked);
}}
type="checkbox"
/>
<svg
className="w-[1em] h-[1em] text-lg"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"
stroke="var(--input-border)"
/>
{!!props.wordWrap && <path d="m9 12 2 2 4-4" />}
</svg>
Wrap
</label>
);
});

export const useEditorWrap: (
initialValue: boolean
) => [boolean, () => JSX.Element] = (initialValue) => {
const [wordWrap, setWordWrap] = useState(initialValue);

return [
wordWrap,
() => (
<label className="text-base flex items-center gap-2 text-[--text-muted] hover:text-[--text] cursor-pointer select-none">
<input
checked={wordWrap}
className="hidden"
onChange={(e) => {
setWordWrap(e.target.checked);
}}
type="checkbox"
/>
<svg
className="w-[1em] h-[1em] text-lg"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"
stroke="var(--input-border)"
/>
{!!wordWrap && <path d="m9 12 2 2 4-4" />}
</svg>
Wrap
</label>
),
() => <Wrap wordWrap={wordWrap} setWordWrap={setWordWrap} />,
];
};
Loading

0 comments on commit 28e723b

Please sign in to comment.