"use client"; import { Circle } from "lucide-react"; import { cn } from "@/lib/utils"; import { OpacitySwatchIcon } from "@/components/slide-editor/toolbar/OpacitySwatchIcon"; import { ColorField, NumberField, Panel, SliderField, } from "@/components/slide-editor/shapes/ShapeToolbar"; type RawRecord = Record; type LinePanelId = "line-width" | "line-color" | "line-style" | "line-opacity"; export type TemplateV2LineToolbarElement = RawRecord & { type: "line"; stroke?: RawRecord | null; }; const LINE_STYLE_OPTIONS: Array<{ key: "solid" | "dashed" | "dotted"; label: string; dash: number[]; }> = [ { key: "solid", label: "Solid", dash: [] }, { key: "dashed", label: "Dashed", dash: [10, 6] }, { key: "dotted", label: "Dotted", dash: [2, 4] }, ]; function asRecord(value: unknown): RawRecord { return value && typeof value === "object" && !Array.isArray(value) ? (value as RawRecord) : {}; } function readNumber(value: unknown, fallback = 0) { return typeof value === "number" && Number.isFinite(value) ? value : fallback; } function readColor(value: unknown, fallback: string) { const color = typeof value === "string" && value ? value : fallback; return color.startsWith("#") ? color : `#${color}`; } function lineStyleLabel(dash: unknown) { const dashArray = Array.isArray(dash) ? dash .map((item) => (typeof item === "number" && Number.isFinite(item) ? item : null)) .filter((item): item is number => item != null && item >= 0) : []; const matched = LINE_STYLE_OPTIONS.find( (option) => option.dash.length === dashArray.length && option.dash.every((value, index) => value === dashArray[index]), ); return matched ?? LINE_STYLE_OPTIONS[0]; } function LineWidthIcon() { return (
); } export function isTemplateV2LineToolbarElement( element: RawRecord | null | undefined, ): element is TemplateV2LineToolbarElement { return element?.type === "line"; } export function TemplateV2LineToolbarControls({ element, onChange, onToggle, openPanel, }: { element: TemplateV2LineToolbarElement; onChange: (changes: RawRecord) => void; onToggle: (panel: LinePanelId) => void; openPanel: string | null; }) { const stroke = asRecord(element.stroke); const strokeColor = readColor(stroke.color, "#191919"); const strokeOpacity = Math.max(0, Math.min(1, readNumber(stroke.opacity, 1))); const strokeWidth = Math.max(0, Math.min(8, readNumber(stroke.width, 1))); const currentStyle = lineStyleLabel(stroke.dash); const setStroke = (nextStroke: RawRecord) => { onChange({ stroke: { ...stroke, ...nextStroke } }); }; return ( <>
{openPanel === "line-width" ? ( setStroke({ width })} /> ) : null}
{openPanel === "line-color" ? ( setStroke({ color })} /> ) : null}
{openPanel === "line-style" ? ( {LINE_STYLE_OPTIONS.map((option) => ( ))} ) : null}
{openPanel === "line-opacity" ? ( `${Math.round(value * 100)}%`} onCommit={(opacity) => setStroke({ opacity })} /> ) : null}
); } function LinePreview({ dash }: { dash: number[] }) { return ( ); }