mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-10 03:51:25 +00:00
Add color picker to contextual menu for text
This commit is contained in:
1 parent
92952eaf95
commit
0489038dc4
8 files changed
+74
-17
No files matched your search
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) }}
|
||||
/>
|
||||
</Transition>
|
||||
);
|
||||
|
||||
@@ -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<HTMLButtonElement> = (
|
||||
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 (
|
||||
<ToolbarButton
|
||||
icon={buttonDatum.icon}
|
||||
tooltip={buttonDatum.tooltip}
|
||||
key={idx}
|
||||
buttonProps={buttonProps}
|
||||
/>
|
||||
);
|
||||
if (!buttonProps || buttonProps.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buttonDatum.name !== ToolbarNodeButtonNames.COLOR) {
|
||||
return (
|
||||
<ToolbarButton
|
||||
icon={buttonDatum.icon}
|
||||
tooltip={buttonDatum.tooltip}
|
||||
key={idx}
|
||||
buttonProps={buttonProps}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<ColorPicker color={color} onChange={onColorChange} faIcon={faPalette} borderStyle="" />
|
||||
)
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -7,4 +7,5 @@ export enum ToolbarNodeButtonNames {
|
||||
MOVE_LAYER_UP = "MOVE_LAYER_UP",
|
||||
MOVE_LAYER_DOWN = "MOVE_LAYER_DOWN",
|
||||
DOWNLOAD = "DOWNLOAD",
|
||||
COLOR = "COLOR",
|
||||
}
|
||||
@@ -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 (
|
||||
<Popover className="relative">
|
||||
<PopoverButton className="flex size-10 flex-col items-center gap-1 rounded-md border p-2">
|
||||
<FontAwesomeIcon icon={faFont} />
|
||||
<span className="h-1 w-full" style={{ backgroundColor: prevColor }} />
|
||||
<PopoverButton className={twMerge(
|
||||
"flex size-10 flex-col items-center gap-1 rounded-md p-2",
|
||||
borderStyle
|
||||
)}>
|
||||
<FontAwesomeIcon icon={faIcon} color={prevColor} />
|
||||
{showBar && <span className="h-1 w-full" style={{ backgroundColor: prevColor }} />}
|
||||
</PopoverButton>
|
||||
<PopoverPanel
|
||||
anchor="bottom"
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface ContextualToolbarProps extends ContextualUi {
|
||||
locked: boolean | "unknown";
|
||||
lockDisabled: boolean;
|
||||
buttonStates: ButtonStates;
|
||||
color: string;
|
||||
}
|
||||
interface PartialContextualToolbarProps
|
||||
extends Partial<Omit<ContextualToolbarProps, "buttonStates">> {
|
||||
@@ -32,6 +33,7 @@ const toolbarNodeSignal = signal<ContextualToolbarProps>({
|
||||
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<ButtonStates> }) {
|
||||
const prevButtonStates = toolbarNodeSignal.value.buttonStates;
|
||||
toolbarNodeSignal.value = {
|
||||
|
||||
Reference in new issue
Block a user