Skip to content

Commit

Permalink
feat: context menu (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
QuiiBz authored Mar 29, 2024
1 parent 6f775e7 commit 935e86f
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 100 deletions.
245 changes: 154 additions & 91 deletions apps/dashboard/src/components/Element.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion -- we know it's defined */
import { useEffect, useMemo, useRef, useState } from "react";
import { clsx } from "clsx";
import { Box } from "@radix-ui/themes";
import { Box, ContextMenu } from "@radix-ui/themes";
import type { OGElement } from "../lib/types";
import { createElementStyle, createImgElementStyle } from "../lib/elements";
import { useElementsStore } from "../stores/elementsStore";
Expand All @@ -21,6 +21,8 @@ export function Element({ element }: ElementProps) {
);
const updateElement = useElementsStore((state) => state.updateElement);
const removeElement = useElementsStore((state) => state.removeElement);
const { undo, redo, pastStates, futureStates } =
useElementsStore.temporal.getState();

const isSelected = selectedElementId === element.id;
const Tag = element.tag;
Expand Down Expand Up @@ -287,96 +289,157 @@ export function Element({ element }: ElementProps) {
}

return (
<Tag
className={clsx(
"element cursor-default select-none outline-1 outline-offset-[3px] hover:outline",
{ "outline cursor-move": isSelected },
{ "!outline !cursor-text": isEditing },
{ "!outline-dashed": element.tag === "span" },
)}
style={{ ...style, outlineColor: "var(--accent-track)" }}
id={`element-${element.id}`}
// @ts-expect-error wtf?
ref={elementRef}
>
{element.tag === "p" ? element.content : null}
{element.tag === "span" ? "Dynamic text" : null}
{element.tag === "div" && element.backgroundImage ? (
<img
alt=""
src={element.backgroundImage}
style={{
pointerEvents: "none",
...createImgElementStyle(element),
width: "100%",
height: "100%",
<ContextMenu.Root>
<ContextMenu.Trigger>
<Tag
className={clsx(
"element cursor-default select-none outline-1 outline-offset-[3px] hover:outline",
{ "outline cursor-move": isSelected },
{ "!outline !cursor-text": isEditing },
{ "!outline-dashed": element.tag === "span" },
)}
style={{ ...style, outlineColor: "var(--accent-track)" }}
id={`element-${element.id}`}
// @ts-expect-error wtf?
ref={elementRef}
>
{element.tag === "p" ? element.content : null}
{element.tag === "span" ? "Dynamic text" : null}
{element.tag === "div" && element.backgroundImage ? (
<img
alt=""
src={element.backgroundImage}
style={{
pointerEvents: "none",
...createImgElementStyle(element),
width: "100%",
height: "100%",
}}
/>
) : null}
{isSelected ? (
<>
<Box
as="span"
className="handle top-left"
height="10px"
position="absolute"
style={{
border: "1px solid var(--accent-track)",
borderRadius: "100%",
backgroundColor: "var(--gray-contrast)",
}}
width="10px"
/>
<Box
as="span"
className="handle top-right"
height="10px"
position="absolute"
style={{
border: "1px solid var(--accent-track)",
borderRadius: "100%",
backgroundColor: "var(--gray-contrast)",
}}
width="10px"
/>
<Box
as="span"
className="handle bottom-left"
height="10px"
position="absolute"
style={{
border: "1px solid var(--accent-track)",
borderRadius: "100%",
backgroundColor: "var(--gray-contrast)",
}}
width="10px"
/>
<Box
as="span"
className="handle bottom-right"
height="10px"
position="absolute"
style={{
border: "1px solid var(--accent-track)",
borderRadius: "100%",
backgroundColor: "var(--gray-contrast)",
}}
width="10px"
/>
<Box
as="span"
className="handle top-center"
height="10px"
position="absolute"
style={{
border: "1px solid var(--accent-track)",
borderRadius: "100%",
backgroundColor: "var(--gray-contrast)",
}}
width="10px"
/>
</>
) : null}
</Tag>
</ContextMenu.Trigger>
<ContextMenu.Content variant="soft">
<ContextMenu.Item
onClick={() => {
const event = new KeyboardEvent("keydown", {
key: "c",
ctrlKey: true,
});

document.body.dispatchEvent(event);
}}
shortcut="⌘ C"
>
Copy
</ContextMenu.Item>
<ContextMenu.Item
onClick={() => {
const event = new KeyboardEvent("keydown", {
key: "v",
ctrlKey: true,
});

document.body.dispatchEvent(event);
}}
shortcut="⌘ V"
>
Paste
</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item
disabled={pastStates.length === 0}
onClick={() => {
undo();
}}
shortcut="⌘ Z"
>
Undo
</ContextMenu.Item>
<ContextMenu.Item
disabled={futureStates.length === 0}
onClick={() => {
redo();
}}
shortcut="⌘ ⇧ Z"
>
Redo
</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item
color="red"
onClick={() => {
removeElement(element.id);
}}
/>
) : null}
{isSelected ? (
<>
<Box
as="span"
className="handle top-left"
height="10px"
position="absolute"
style={{
border: "1px solid var(--accent-track)",
borderRadius: "100%",
backgroundColor: "var(--gray-contrast)",
}}
width="10px"
/>
<Box
as="span"
className="handle top-right"
height="10px"
position="absolute"
style={{
border: "1px solid var(--accent-track)",
borderRadius: "100%",
backgroundColor: "var(--gray-contrast)",
}}
width="10px"
/>
<Box
as="span"
className="handle bottom-left"
height="10px"
position="absolute"
style={{
border: "1px solid var(--accent-track)",
borderRadius: "100%",
backgroundColor: "var(--gray-contrast)",
}}
width="10px"
/>
<Box
as="span"
className="handle bottom-right"
height="10px"
position="absolute"
style={{
border: "1px solid var(--accent-track)",
borderRadius: "100%",
backgroundColor: "var(--gray-contrast)",
}}
width="10px"
/>
<Box
as="span"
className="handle top-center"
height="10px"
position="absolute"
style={{
border: "1px solid var(--accent-track)",
borderRadius: "100%",
backgroundColor: "var(--gray-contrast)",
}}
width="10px"
/>
</>
) : null}
</Tag>
shortcut="⌫"
>
Delete
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Root>
);
}
11 changes: 2 additions & 9 deletions apps/dashboard/src/components/OgEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ export function OgEditor({ imageId, width, height }: OgProviderProps) {
}, [imageId, loadImage, setSelectedImageId]);

useEffect(() => {
function onContextMenu(event: MouseEvent) {
event.preventDefault();
// TODO
}

function onClick(event: MouseEvent) {
const element = event.target as HTMLElement;

Expand Down Expand Up @@ -193,19 +188,17 @@ export function OgEditor({ imageId, width, height }: OgProviderProps) {
const ref = rootRef.current;

if (ref) {
ref.addEventListener("contextmenu", onContextMenu);
ref.addEventListener("click", onClick);
}

document.addEventListener("keydown", onKeyDown);
document.body.addEventListener("keydown", onKeyDown);

return () => {
if (ref) {
ref.removeEventListener("contextmenu", onContextMenu);
ref.removeEventListener("click", onClick);
}

document.removeEventListener("keydown", onKeyDown);
document.body.removeEventListener("keydown", onKeyDown);
};
}, [
rootRef,
Expand Down

0 comments on commit 935e86f

Please sign in to comment.