"use client"; import { CircleAlertIcon, SunIcon, MoonIcon } from "lucide-react"; import { Select } from "@/components/assistant-ui/select"; import { Switch } from "@/components/ui/switch"; import { ThemeColorPicker, OptionalThemeColorPicker, } from "@/components/shared/color-picker"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/radix/tooltip"; import { BORDER_RADIUSES, CODE_HIGHLIGHT_THEMES, DEFAULT_COLORS, FONT_FAMILIES, FONT_SIZES, LOADING_INDICATORS, MAX_WIDTHS, MESSAGE_SPACINGS, TYPING_INDICATORS, USER_MESSAGE_POSITIONS, type BuilderConfig, type BorderRadius, type CodeHighlightTheme, type FontSize, type LoadingIndicator, type MessageSpacing, type ThemeColor, type TypingIndicator, } from "./types"; import { PRESETS } from "./presets"; import { analytics } from "@/lib/analytics"; interface BuilderControlsProps { config: BuilderConfig; onChange: (config: BuilderConfig) => void; } export function BuilderControls({ config, onChange }: BuilderControlsProps) { const updateComponents = (updates: Partial) => { onChange({ ...config, components: { ...config.components, ...updates }, }); }; const updateStyles = (updates: Partial) => { onChange({ ...config, styles: { ...config.styles, ...updates }, }); }; const updateColor = ( key: K, value: BuilderConfig["styles"]["colors"][K], ) => { onChange({ ...config, styles: { ...config.styles, colors: { ...config.styles.colors, [key]: value }, }, }); }; const updateOptionalColor = < K extends keyof BuilderConfig["styles"]["colors"], >( key: K, value: ThemeColor | undefined, ) => { const newColors = { ...config.styles.colors }; if (value === undefined) { delete newColors[key]; } else { newColors[key] = value; } onChange({ ...config, styles: { ...config.styles, colors: newColors, }, }); }; const updateActionBar = ( updates: Partial, ) => { onChange({ ...config, components: { ...config.components, actionBar: { ...config.components.actionBar, ...updates }, }, }); }; const { components, styles } = config; return (
Preset
} withDivider={false} >
updateStyles({ userMessagePosition: value as "left" | "right", }) } options={USER_MESSAGE_POSITIONS} /> } /> updateColor("userMessage", value)} /> } /> { if (enabled) { updateOptionalColor( "assistantMessage", DEFAULT_COLORS.background, ); } else { updateOptionalColor("assistantMessage", undefined); } }} color={styles.colors.assistantMessage} defaultColor={DEFAULT_COLORS.background} onColorChange={(color) => updateOptionalColor("assistantMessage", color) } /> updateStyles({ messageSpacing: value as MessageSpacing }) } options={MESSAGE_SPACINGS} /> } /> updateComponents({ editMessage: checked }) } /> } /> updateComponents({ branchPicker: checked }) } /> } />
updateComponents({ threadWelcome: checked }) } /> } /> updateComponents({ scrollToBottom: checked }) } /> } /> updateStyles({ maxWidth: value })} options={MAX_WIDTHS} /> } />
}>
updateComponents({ attachments: checked }) } /> } /> { if (enabled) { updateOptionalColor("composer", DEFAULT_COLORS.composer); } else { updateOptionalColor("composer", undefined); } }} color={styles.colors.composer} defaultColor={DEFAULT_COLORS.composer} onColorChange={(color) => updateOptionalColor("composer", color)} />
updateComponents({ markdown: checked }) } /> } /> {components.markdown && ( Syntax highlighting powered by{" "} Shiki } control={ { const preset = PRESETS.find((p) => p.id === id); if (preset) { analytics.builder.presetSelected(preset.name); onChange(preset.config); } }} options={options} placeholder="Custom" /> ); }