返回 presentation-ai
ColorControl.tsx
1 "use client";
2
3 import { Baseline, PaintBucket, RotateCcw } from "lucide-react";
4 import { KEYS } from "platejs";
5
6 import {
7 BUTTON_ELEMENT,
8 CONTRIBUTOR_ELEMENT,
9 LABEL_ELEMENT,
10 PRESENTATION_TITLE_ELEMENT,
11 } from "@/components/notebook/presentation/editor/lib";
12 import { ToolbarButton, ToolbarGroup } from "@/components/plate/ui/toolbar";
13 import ColorPicker from "@/components/ui/color-picker";
14 import { useToolbarContext } from "./ToolbarContext";
15
16 const BACKGROUND_COLOR_ELEMENT_TYPES = new Set<string>([
17 BUTTON_ELEMENT,
18 CONTRIBUTOR_ELEMENT,
19 KEYS.callout,
20 LABEL_ELEMENT,
21 PRESENTATION_TITLE_ELEMENT,
22 ]);
23 const DEFAULT_PICKER_COLOR = "#3b82f6";
24
25 function isHexColor(value: string) {
26 return /^#[0-9a-f]{6}$/i.test(value);
27 }
28
29 export function ColorControl() {
30 const {
31 element,
32 elementType,
33 currentBackgroundColor,
34 currentColor,
35 currentTextColor,
36 handleNodePropertyUpdate,
37 } = useToolbarContext();
38 const shouldShowBackgroundColor =
39 BACKGROUND_COLOR_ELEMENT_TYPES.has(elementType);
40 const hasCustomBackgroundColor =
41 (element as { backgroundColor?: string })?.backgroundColor !== undefined;
42 const hasCustomTextColor =
43 (element as { textColor?: string })?.textColor !== undefined;
44 const hasCustomColor = (element as { color?: string })?.color !== undefined;
45 const colorProperty = shouldShowBackgroundColor ? "textColor" : "color";
46 const colorValue = shouldShowBackgroundColor
47 ? currentTextColor
48 : currentColor;
49 const pickerColor = isHexColor(colorValue)
50 ? colorValue
51 : DEFAULT_PICKER_COLOR;
52 const hasCustomEditableColor = shouldShowBackgroundColor
53 ? hasCustomTextColor || hasCustomColor
54 : hasCustomColor;
55
56 return (
57 <ToolbarGroup>
58 {shouldShowBackgroundColor && (
59 <ColorPicker
60 value={currentBackgroundColor}
61 onChange={(color) => {
62 handleNodePropertyUpdate("backgroundColor", color);
63 }}
64 >
65 <ToolbarButton tooltip="Choose Background Color" size="sm">
66 <PaintBucket className="size-4" />
67 </ToolbarButton>
68 </ColorPicker>
69 )}
70
71 {shouldShowBackgroundColor && hasCustomBackgroundColor && (
72 <ToolbarButton
73 onClick={() => {
74 handleNodePropertyUpdate("backgroundColor", undefined);
75 }}
76 tooltip="Reset Background Color"
77 size="sm"
78 className="gap-1"
79 >
80 <RotateCcw className="size-4" />
81 </ToolbarButton>
82 )}
83
84 <ColorPicker
85 value={pickerColor}
86 onChange={(color) => {
87 handleNodePropertyUpdate(colorProperty, color);
88 }}
89 >
90 <ToolbarButton tooltip="Choose Color" size="sm">
91 {shouldShowBackgroundColor ? (
92 <Baseline className="size-4" />
93 ) : (
94 <span
95 className="size-4 rounded-[3px] border border-border shadow-inner"
96 style={{ backgroundColor: colorValue }}
97 />
98 )}
99 </ToolbarButton>
100 </ColorPicker>
101
102 {hasCustomEditableColor && (
103 <ToolbarButton
104 onClick={() => {
105 handleNodePropertyUpdate(colorProperty, undefined);
106 if (shouldShowBackgroundColor) {
107 handleNodePropertyUpdate("color", undefined);
108 }
109 }}
110 tooltip="Reset Color"
111 size="sm"
112 className="gap-1"
113 >
114 <RotateCcw className="size-4" />
115 </ToolbarButton>
116 )}
117 </ToolbarGroup>
118 );
119 }
120
120 lines Plain Text