import type { CustomThemeColors } from '../types' import { CustomThemePreview } from './CustomThemePreview' import './Modal.css' import './ThemeBuilderModal.css' interface ColorField { key: keyof Omit label: string } interface ThemeBuilderModalProps { colorFields: ColorField[] name: string onNameChange: (name: string) => void colors: CustomThemeColors onColorChange: (key: keyof CustomThemeColors, value: string) => void highlightedField: keyof CustomThemeColors | null onHighlight: (field: keyof CustomThemeColors | null) => void error: string | null saving: boolean onSave: () => void onCancel: () => void } // Same editor as ProfileModal.tsx used to render inline, pulled out into its // own wider dialog (#46) -- the profile modal's .modal is capped at // min(380px, 100%), which cramped the CustomThemePreview mockup that's // supposed to make the color-to-UI mapping easy to see. Nested on top of // ProfileModal rather than replacing it, same stacked-dialog pattern as // ImageLightbox/FilePreviewModal opening over MessageList. export function ThemeBuilderModal({ colorFields, name, onNameChange, colors, onColorChange, highlightedField, onHighlight, error, saving, onSave, onCancel, }: ThemeBuilderModalProps) { return (
e.stopPropagation()}>

Edit theme

onNameChange(e.target.value)} placeholder="Theme name" maxLength={50} /> {/* Full modal width, not sharing a column with the fields below -- the whole point of this dialog over the old inline editor is room for this mockup to read at a legible size. */}
{colorFields.map((field) => ( ))}
Native controls (scrollbars, form inputs)
{error &&

{error}

}
) }