From 0489038dc48feac39bbcb2be9c578095b739e685 Mon Sep 17 00:00:00 2001 From: Tanish Manku Date: Wed, 19 Feb 2025 18:21:11 -0800 Subject: [PATCH] Add color picker to contextual menu for text --- .../NodesManagers/SelectionManager.ts | 2 + .../NodesManagers/ToolbarNodeUtilities.ts | 10 +++-- .../ContextualToolbarNode.tsx | 2 + .../features/ToolbarNode/ToolbarNode.tsx | 39 ++++++++++++++----- .../components/features/ToolbarNode/data.ts | 6 +++ .../components/features/ToolbarNode/enums.ts | 1 + .../components/ui/TextEditor/ColorPicker.tsx | 18 +++++++-- .../src/signals/uiAccess/toolbarNode.ts | 13 +++++++ 8 files changed, 74 insertions(+), 17 deletions(-) diff --git a/frontend/realtime/src/KonvaApp/NodesManagers/SelectionManager.ts b/frontend/realtime/src/KonvaApp/NodesManagers/SelectionManager.ts index b903add420..8a7858b66e 100644 --- a/frontend/realtime/src/KonvaApp/NodesManagers/SelectionManager.ts +++ b/frontend/realtime/src/KonvaApp/NodesManagers/SelectionManager.ts @@ -279,8 +279,10 @@ export class SelectionManager { } if (node instanceof TextNode) { showOrUpdate({ + // TODO: Add ID to identify/mutate the color? locked: node.isLocked(), buttonStates: getTextNodeButtonStates({ locked: node.isLocked() }), + color: node.getNodeData({ x: 0, y: 0 }).textNodeData?.color ?? "#000000", }); } if (node instanceof VideoNode) { diff --git a/frontend/realtime/src/KonvaApp/NodesManagers/ToolbarNodeUtilities.ts b/frontend/realtime/src/KonvaApp/NodesManagers/ToolbarNodeUtilities.ts index 8a33cb2611..9b82c82d5d 100644 --- a/frontend/realtime/src/KonvaApp/NodesManagers/ToolbarNodeUtilities.ts +++ b/frontend/realtime/src/KonvaApp/NodesManagers/ToolbarNodeUtilities.ts @@ -51,7 +51,8 @@ export function getImageNodeButtonStates( buttonName === ButtonNames.AI_STYLIZE || buttonName === ButtonNames.SEGMENTATION || buttonName === ButtonNames.DOWNLOAD || - buttonName === ButtonNames.CHROMA + buttonName === ButtonNames.CHROMA || + buttonName === ButtonNames.COLOR ) { buttonStates[buttonName] = { disabled: true, @@ -130,7 +131,9 @@ export function getVideoNodeButtonStates( return buttonStates; } // soon to come feature is disabled - if (buttonName === ButtonNames.AI_STYLIZE) { + if (buttonName === ButtonNames.AI_STYLIZE || + buttonName === ButtonNames.COLOR + ) { buttonStates[buttonName] = { disabled: true, hidden: true, @@ -170,7 +173,8 @@ export function getMultiSelectButtonStates( buttonName === ButtonNames.AI_STYLIZE || buttonName === ButtonNames.SEGMENTATION || buttonName === ButtonNames.DOWNLOAD || - buttonName === ButtonNames.CHROMA + buttonName === ButtonNames.CHROMA || + buttonName === ButtonNames.COLOR ) { buttonStates[buttonName] = { disabled: true, diff --git a/frontend/realtime/src/KonvaRootComponent/ContextualToolbarNode.tsx b/frontend/realtime/src/KonvaRootComponent/ContextualToolbarNode.tsx index 5a362ade64..16d32a0c0d 100644 --- a/frontend/realtime/src/KonvaRootComponent/ContextualToolbarNode.tsx +++ b/frontend/realtime/src/KonvaRootComponent/ContextualToolbarNode.tsx @@ -71,6 +71,8 @@ export const ContextualToolbarNode = () => { onLockClicked={(e) => { dispatchUiEvents.toolbarNode.lock(e); }} + color={uiAccess.toolbarNode.signal.value.color} + onColorChange={(color) => { uiAccess.toolbarNode.setColor(color) }} /> ); diff --git a/frontend/realtime/src/components/features/ToolbarNode/ToolbarNode.tsx b/frontend/realtime/src/components/features/ToolbarNode/ToolbarNode.tsx index 6988b11ac2..b720864a8f 100644 --- a/frontend/realtime/src/components/features/ToolbarNode/ToolbarNode.tsx +++ b/frontend/realtime/src/components/features/ToolbarNode/ToolbarNode.tsx @@ -4,14 +4,19 @@ import { faLockKeyholeOpen, faLockKeyhole, faUnlockKeyhole, + faPalette, } from "@fortawesome/pro-solid-svg-icons"; import { ToolbarButton, ToolbarButtonProps, } from "~/components/features/ToolbarButton"; -import { paperWrapperStyles } from "~/components/styles"; +import { paperWrapperStyles, toolTipStyles } from "~/components/styles"; import { ToolbarNodeButtonNames } from "./enums"; import { ToolbarNodeButtonData } from "./data"; +import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react"; +import { Fragment } from "react/jsx-runtime"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { ColorPicker } from "~/components/ui/TextEditor/ColorPicker"; export interface ToolbarNodeProps { disabled?: boolean; @@ -24,6 +29,8 @@ export interface ToolbarNodeProps { buttonsProps?: { [key in ToolbarNodeButtonNames]: ToolbarButtonProps; }; + color?: string; + onColorChange?: (color: string) => void; } export const ToolbarNode = ({ disabled, @@ -31,6 +38,8 @@ export const ToolbarNode = ({ lockDisabled, onLockClicked, buttonsProps, + color = "#000000", + onColorChange = () => { }, }: ToolbarNodeProps) => { const handleOnLockClicked: React.MouseEventHandler = ( e, @@ -53,7 +62,7 @@ export const ToolbarNode = ({ className: twMerge( locked && "text-primary hover:bg-primary hover:text-white", lockDisabledOrUnknown && - "text-secondary-300 hover:text-secondary-300", + "text-secondary-300 hover:text-secondary-300", ), disabled: lockDisabledOrUnknown, }} @@ -73,14 +82,24 @@ export const ToolbarNode = ({ {ToolbarNodeButtonData.map((buttonDatum, idx) => { const buttonProps = buttonsProps?.[buttonDatum.name]; - return ( - - ); + if (!buttonProps || buttonProps.hidden) { + return; + } + + if (buttonDatum.name !== ToolbarNodeButtonNames.COLOR) { + return ( + + ); + } else { + return ( + + ) + } })} ); diff --git a/frontend/realtime/src/components/features/ToolbarNode/data.ts b/frontend/realtime/src/components/features/ToolbarNode/data.ts index 4cda8019ac..c215e5ed8b 100644 --- a/frontend/realtime/src/components/features/ToolbarNode/data.ts +++ b/frontend/realtime/src/components/features/ToolbarNode/data.ts @@ -8,6 +8,7 @@ import { faTrashCan, faVectorSquare, faDownload, + faPalette, } from "@fortawesome/pro-solid-svg-icons"; export const ToolbarNodeButtonData = [ @@ -16,6 +17,11 @@ export const ToolbarNodeButtonData = [ icon: faVectorSquare, tooltip: "Move", }, + { + name: ButtonNames.COLOR, + icon: faPalette, + tooltip: "Color", + }, { name: ButtonNames.CHROMA, icon: faTransporter, diff --git a/frontend/realtime/src/components/features/ToolbarNode/enums.ts b/frontend/realtime/src/components/features/ToolbarNode/enums.ts index a79f621f31..e4c559695a 100644 --- a/frontend/realtime/src/components/features/ToolbarNode/enums.ts +++ b/frontend/realtime/src/components/features/ToolbarNode/enums.ts @@ -7,4 +7,5 @@ export enum ToolbarNodeButtonNames { MOVE_LAYER_UP = "MOVE_LAYER_UP", MOVE_LAYER_DOWN = "MOVE_LAYER_DOWN", DOWNLOAD = "DOWNLOAD", + COLOR = "COLOR", } diff --git a/frontend/realtime/src/components/ui/TextEditor/ColorPicker.tsx b/frontend/realtime/src/components/ui/TextEditor/ColorPicker.tsx index 2cdf7a0d6e..c56663236b 100644 --- a/frontend/realtime/src/components/ui/TextEditor/ColorPicker.tsx +++ b/frontend/realtime/src/components/ui/TextEditor/ColorPicker.tsx @@ -1,6 +1,6 @@ import { ChangeEvent, useState } from "react"; import { twMerge } from "tailwind-merge"; -import { faFont, faHashtag } from "@fortawesome/pro-solid-svg-icons"; +import { faFont, faHashtag, IconDefinition } from "@fortawesome/pro-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react"; import { HexColorPicker } from "react-colorful"; @@ -12,9 +12,15 @@ import { paperWrapperStyles } from "~/components/styles"; export const ColorPicker = ({ color: prevColor, onChange, + faIcon = faFont, + borderStyle = "border", + showBar = true, }: { color: string; onChange: (newColor: string) => void; + faIcon?: IconDefinition; + borderStyle?: string; + showBar?: boolean; }) => { const [{ currColor, textInput }, setStates] = useState<{ currColor: string; @@ -44,11 +50,15 @@ export const ColorPicker = ({ })); } }; + return ( - - - + + + {showBar && } > { @@ -32,6 +33,7 @@ const toolbarNodeSignal = signal({ locked: false, lockDisabled: false, buttonStates: initButtonStates(), + color: "#000000", }); export const toolbarNode = { @@ -77,6 +79,11 @@ export const toolbarNode = { hidden: false, active: buttonStates[ButtonNames.TRANSFORM].active, }, + [ButtonNames.COLOR]: { + disabled: locked, + hidden: false, + active: buttonStates[ButtonNames.COLOR].active, + }, }, locked: locked, }; @@ -135,6 +142,12 @@ export const toolbarNode = { }, }; }, + setColor(color: string) { + toolbarNodeSignal.value = { + ...toolbarNodeSignal.value, + color, + } + }, batchButtonStates({ buttonStates }: { buttonStates: Partial }) { const prevButtonStates = toolbarNodeSignal.value.buttonStates; toolbarNodeSignal.value = {