@runtypelabs/persona 3.5.1 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +30 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.global.js +41 -41
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +29 -29
- package/dist/index.js.map +1 -1
- package/dist/theme-editor.cjs +17728 -0
- package/dist/theme-editor.d.cts +3857 -0
- package/dist/theme-editor.d.ts +3857 -0
- package/dist/theme-editor.js +17623 -0
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +14 -0
- package/dist/theme-reference.d.ts +14 -0
- package/dist/theme-reference.js +1 -1
- package/dist/widget.css +29 -25
- package/package.json +9 -7
- package/src/components/artifact-card.ts +1 -1
- package/src/components/composer-builder.ts +16 -29
- package/src/components/demo-carousel.ts +4 -4
- package/src/components/event-stream-view.ts +1 -1
- package/src/components/header-builder.ts +2 -2
- package/src/components/launcher.ts +9 -0
- package/src/components/message-bubble.ts +9 -3
- package/src/components/suggestions.ts +1 -1
- package/src/defaults.ts +9 -9
- package/src/styles/widget.css +29 -25
- package/src/theme-editor/color-utils.ts +252 -0
- package/src/theme-editor/index.ts +130 -0
- package/src/theme-editor/presets.ts +144 -0
- package/src/theme-editor/preview-utils.ts +265 -0
- package/src/theme-editor/preview.ts +445 -0
- package/src/theme-editor/role-mappings.ts +331 -0
- package/src/theme-editor/sections.ts +952 -0
- package/src/theme-editor/state.ts +298 -0
- package/src/theme-editor/types.ts +177 -0
- package/src/theme-editor.ts +2 -0
- package/src/types/theme.ts +1 -0
- package/src/ui.ts +53 -58
- package/src/utils/plugins.ts +1 -1
- package/src/utils/theme.test.ts +10 -8
- package/src/utils/theme.ts +11 -11
- package/src/utils/tokens.ts +88 -41
- package/widget.css +0 -1
|
@@ -0,0 +1,952 @@
|
|
|
1
|
+
/** Declarative section/field definitions for the theme editor (pure data — no DOM, no render logic) */
|
|
2
|
+
|
|
3
|
+
import type { SectionDef, TabDef, SubGroupDef, FieldDef } from './types';
|
|
4
|
+
import { COLOR_FAMILIES } from './color-utils';
|
|
5
|
+
import {
|
|
6
|
+
ROLE_SURFACES,
|
|
7
|
+
ROLE_HEADER,
|
|
8
|
+
ROLE_USER_MESSAGES,
|
|
9
|
+
ROLE_ASSISTANT_MESSAGES,
|
|
10
|
+
ROLE_PRIMARY_ACTIONS,
|
|
11
|
+
ROLE_INPUT,
|
|
12
|
+
ROLE_LINKS_FOCUS,
|
|
13
|
+
ROLE_BORDERS,
|
|
14
|
+
} from './role-mappings';
|
|
15
|
+
|
|
16
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
17
|
+
// STYLE TAB — brand colors, chat colors, typography, shape, etc.
|
|
18
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
19
|
+
|
|
20
|
+
const themeModeSectionDef: SectionDef = {
|
|
21
|
+
id: 'theme-mode',
|
|
22
|
+
title: 'Runtime Theme',
|
|
23
|
+
description: 'Controls how the shipped widget picks light or dark mode.',
|
|
24
|
+
collapsed: false,
|
|
25
|
+
fields: [
|
|
26
|
+
{
|
|
27
|
+
id: 'theme-mode',
|
|
28
|
+
label: 'Runtime Theme',
|
|
29
|
+
description: 'Always Light, Always Dark, or follow the visitor system preference',
|
|
30
|
+
type: 'select',
|
|
31
|
+
path: 'colorScheme',
|
|
32
|
+
defaultValue: 'auto',
|
|
33
|
+
options: [
|
|
34
|
+
{ value: 'light', label: 'Light' },
|
|
35
|
+
{ value: 'dark', label: 'Dark' },
|
|
36
|
+
{ value: 'auto', label: 'Follow System' },
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const brandColorsSectionDef: SectionDef = {
|
|
43
|
+
id: 'brand-colors',
|
|
44
|
+
title: 'Brand Colors',
|
|
45
|
+
description: 'Pick your brand colors. A full shade scale is generated automatically for both light and dark themes.',
|
|
46
|
+
collapsed: false,
|
|
47
|
+
fields: [
|
|
48
|
+
{ id: 'brand-primary', label: 'Primary', description: 'Main brand color for buttons, links, and accents', type: 'color', path: 'theme.palette.colors.primary.500', defaultValue: '#171717' },
|
|
49
|
+
{ id: 'brand-secondary', label: 'Secondary', description: 'Supporting brand color', type: 'color', path: 'theme.palette.colors.secondary.500', defaultValue: '#7c3aed' },
|
|
50
|
+
{ id: 'brand-accent', label: 'Accent', description: 'Highlight and decorative color', type: 'color', path: 'theme.palette.colors.accent.500', defaultValue: '#06b6d4' },
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const chatColorsSectionDef: SectionDef = {
|
|
55
|
+
id: 'chat-colors',
|
|
56
|
+
title: 'Chat Colors',
|
|
57
|
+
description: 'Customize the main colors of the chat interface.',
|
|
58
|
+
collapsed: true,
|
|
59
|
+
fields: [
|
|
60
|
+
{ id: 'chat-header-bg', label: 'Header Background', type: 'token-ref', path: 'theme.components.header.background', defaultValue: 'semantic.colors.surface', tokenRef: { tokenType: 'color' } },
|
|
61
|
+
{ id: 'chat-header-icon-bg', label: 'Header Icon Background', type: 'token-ref', path: 'theme.components.header.iconBackground', defaultValue: 'semantic.colors.primary', tokenRef: { tokenType: 'color' } },
|
|
62
|
+
{ id: 'chat-header-icon-fg', label: 'Header Icon Color', type: 'token-ref', path: 'theme.components.header.iconForeground', defaultValue: 'semantic.colors.textInverse', tokenRef: { tokenType: 'color' } },
|
|
63
|
+
{ id: 'chat-header-title-fg', label: 'Header Title Color', type: 'token-ref', path: 'theme.components.header.titleForeground', defaultValue: 'semantic.colors.primary', tokenRef: { tokenType: 'color' } },
|
|
64
|
+
{ id: 'chat-header-subtitle-fg', label: 'Header Subtitle Color', type: 'token-ref', path: 'theme.components.header.subtitleForeground', defaultValue: 'semantic.colors.textMuted', tokenRef: { tokenType: 'color' } },
|
|
65
|
+
{ id: 'chat-header-action-icons-fg', label: 'Header Button Icons', type: 'token-ref', path: 'theme.components.header.actionIconForeground', defaultValue: 'semantic.colors.textMuted', tokenRef: { tokenType: 'color' } },
|
|
66
|
+
{ id: 'chat-msg-user-bg', label: 'User Message Background', type: 'token-ref', path: 'theme.components.message.user.background', defaultValue: 'semantic.colors.primary', tokenRef: { tokenType: 'color' } },
|
|
67
|
+
{ id: 'chat-msg-user-text', label: 'User Message Text', type: 'token-ref', path: 'theme.components.message.user.text', defaultValue: 'semantic.colors.textInverse', tokenRef: { tokenType: 'color' } },
|
|
68
|
+
{ id: 'chat-msg-assistant-bg', label: 'Assistant Message Background', type: 'token-ref', path: 'theme.components.message.assistant.background', defaultValue: 'semantic.colors.container', tokenRef: { tokenType: 'color' } },
|
|
69
|
+
{ id: 'chat-msg-assistant-text', label: 'Assistant Message Text', type: 'token-ref', path: 'theme.components.message.assistant.text', defaultValue: 'semantic.colors.text', tokenRef: { tokenType: 'color' } },
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const typographySectionDef: SectionDef = {
|
|
74
|
+
id: 'typography',
|
|
75
|
+
title: 'Typography',
|
|
76
|
+
collapsed: true,
|
|
77
|
+
fields: [
|
|
78
|
+
{ id: 'typo-font-family', label: 'Font Family', type: 'select', path: 'theme.semantic.typography.fontFamily', defaultValue: 'palette.typography.fontFamily.sans', options: [
|
|
79
|
+
{ value: 'palette.typography.fontFamily.sans', label: 'Sans Serif' },
|
|
80
|
+
{ value: 'palette.typography.fontFamily.serif', label: 'Serif' },
|
|
81
|
+
{ value: 'palette.typography.fontFamily.mono', label: 'Monospace' },
|
|
82
|
+
] },
|
|
83
|
+
{ id: 'typo-font-size', label: 'Base Font Size', type: 'select', path: 'theme.semantic.typography.fontSize', defaultValue: 'palette.typography.fontSize.base', options: [
|
|
84
|
+
{ value: 'palette.typography.fontSize.xs', label: 'Extra Small (0.75rem)' },
|
|
85
|
+
{ value: 'palette.typography.fontSize.sm', label: 'Small (0.875rem)' },
|
|
86
|
+
{ value: 'palette.typography.fontSize.base', label: 'Base (1rem)' },
|
|
87
|
+
{ value: 'palette.typography.fontSize.lg', label: 'Large (1.125rem)' },
|
|
88
|
+
{ value: 'palette.typography.fontSize.xl', label: 'Extra Large (1.25rem)' },
|
|
89
|
+
] },
|
|
90
|
+
{ id: 'typo-font-weight', label: 'Font Weight', type: 'select', path: 'theme.semantic.typography.fontWeight', defaultValue: 'palette.typography.fontWeight.normal', options: [
|
|
91
|
+
{ value: 'palette.typography.fontWeight.normal', label: 'Normal (400)' },
|
|
92
|
+
{ value: 'palette.typography.fontWeight.medium', label: 'Medium (500)' },
|
|
93
|
+
{ value: 'palette.typography.fontWeight.semibold', label: 'Semibold (600)' },
|
|
94
|
+
{ value: 'palette.typography.fontWeight.bold', label: 'Bold (700)' },
|
|
95
|
+
] },
|
|
96
|
+
{ id: 'typo-line-height', label: 'Line Height', type: 'select', path: 'theme.semantic.typography.lineHeight', defaultValue: 'palette.typography.lineHeight.normal', options: [
|
|
97
|
+
{ value: 'palette.typography.lineHeight.tight', label: 'Tight (1.25)' },
|
|
98
|
+
{ value: 'palette.typography.lineHeight.normal', label: 'Normal (1.5)' },
|
|
99
|
+
{ value: 'palette.typography.lineHeight.relaxed', label: 'Relaxed (1.625)' },
|
|
100
|
+
] },
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const launcherStyleSectionDef: SectionDef = {
|
|
105
|
+
id: 'launcher-style',
|
|
106
|
+
title: 'Launcher',
|
|
107
|
+
description: 'Control launcher appearance.',
|
|
108
|
+
collapsed: true,
|
|
109
|
+
fields: [
|
|
110
|
+
{ id: 'style-launcher-size', label: 'Launcher Size', type: 'slider', path: 'theme.components.launcher.size', defaultValue: '60px', slider: { min: 32, max: 80, step: 2 } },
|
|
111
|
+
{ id: 'style-launcher-shape', label: 'Launcher Shape', type: 'select', path: 'theme.components.launcher.borderRadius', defaultValue: 'palette.radius.full', options: [
|
|
112
|
+
{ value: 'palette.radius.md', label: 'Rounded Square' },
|
|
113
|
+
{ value: 'palette.radius.lg', label: 'Rounded' },
|
|
114
|
+
{ value: 'palette.radius.xl', label: 'Very Rounded' },
|
|
115
|
+
{ value: 'palette.radius.full', label: 'Circle' },
|
|
116
|
+
] },
|
|
117
|
+
{ id: 'style-launcher-shadow', label: 'Launcher Shadow', type: 'select', path: 'theme.components.launcher.shadow', defaultValue: 'palette.shadows.lg', options: [
|
|
118
|
+
{ value: 'palette.shadows.none', label: 'None' },
|
|
119
|
+
{ value: 'palette.shadows.sm', label: 'Small' },
|
|
120
|
+
{ value: 'palette.shadows.md', label: 'Medium' },
|
|
121
|
+
{ value: 'palette.shadows.lg', label: 'Large' },
|
|
122
|
+
{ value: 'palette.shadows.xl', label: 'Extra Large' },
|
|
123
|
+
] },
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const shapeSectionDef: SectionDef = {
|
|
128
|
+
id: 'shape',
|
|
129
|
+
title: 'Shape',
|
|
130
|
+
description: 'Control the corner roundness across the widget.',
|
|
131
|
+
collapsed: true,
|
|
132
|
+
fields: [
|
|
133
|
+
{ id: 'radius-sm', label: 'Small', type: 'slider', path: 'theme.palette.radius.sm', defaultValue: '0.125rem', slider: { min: 0, max: 16, step: 1 } },
|
|
134
|
+
{ id: 'radius-md', label: 'Medium', type: 'slider', path: 'theme.palette.radius.md', defaultValue: '0.375rem', slider: { min: 0, max: 24, step: 1 } },
|
|
135
|
+
{ id: 'radius-lg', label: 'Large', type: 'slider', path: 'theme.palette.radius.lg', defaultValue: '0.5rem', slider: { min: 0, max: 32, step: 1 } },
|
|
136
|
+
{ id: 'radius-xl', label: 'Extra Large', type: 'slider', path: 'theme.palette.radius.xl', defaultValue: '0.75rem', slider: { min: 0, max: 48, step: 1 } },
|
|
137
|
+
{ id: 'radius-full', label: 'Full', type: 'slider', path: 'theme.palette.radius.full', defaultValue: '9999px', slider: { min: 0, max: 100, step: 1, isRadiusFull: true } },
|
|
138
|
+
],
|
|
139
|
+
presets: [
|
|
140
|
+
{ id: 'radius-default', label: 'Default', values: { 'theme.palette.radius.sm': '0.125rem', 'theme.palette.radius.md': '0.375rem', 'theme.palette.radius.lg': '0.5rem', 'theme.palette.radius.xl': '0.75rem', 'theme.palette.radius.full': '9999px' } },
|
|
141
|
+
{ id: 'radius-sharp', label: 'Sharp', values: { 'theme.palette.radius.sm': '1px', 'theme.palette.radius.md': '2px', 'theme.palette.radius.lg': '3px', 'theme.palette.radius.xl': '4px', 'theme.palette.radius.full': '4px' } },
|
|
142
|
+
{ id: 'radius-rounded', label: 'Rounded', values: { 'theme.palette.radius.sm': '0.5rem', 'theme.palette.radius.md': '0.75rem', 'theme.palette.radius.lg': '1rem', 'theme.palette.radius.xl': '1.5rem', 'theme.palette.radius.full': '9999px' } },
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const shadowsSectionDef: SectionDef = {
|
|
147
|
+
id: 'shadows',
|
|
148
|
+
title: 'Shadows',
|
|
149
|
+
collapsed: true,
|
|
150
|
+
fields: [
|
|
151
|
+
{ id: 'shadow-sm', label: 'Small', type: 'text', path: 'theme.palette.shadows.sm', defaultValue: '0 1px 2px 0 rgb(0 0 0 / 0.05)' },
|
|
152
|
+
{ id: 'shadow-md', label: 'Medium', type: 'text', path: 'theme.palette.shadows.md', defaultValue: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)' },
|
|
153
|
+
{ id: 'shadow-lg', label: 'Large', type: 'text', path: 'theme.palette.shadows.lg', defaultValue: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)' },
|
|
154
|
+
{ id: 'shadow-xl', label: 'Extra Large', type: 'text', path: 'theme.palette.shadows.xl', defaultValue: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)' },
|
|
155
|
+
],
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const widgetStyleSectionDef: SectionDef = {
|
|
159
|
+
id: 'widget-style',
|
|
160
|
+
title: 'Widget Surface',
|
|
161
|
+
description: 'Adjust the main panel and message bubble treatment.',
|
|
162
|
+
collapsed: true,
|
|
163
|
+
fields: [
|
|
164
|
+
{ id: 'style-panel-radius', label: 'Panel Corner Radius', type: 'select', path: 'theme.components.panel.borderRadius', defaultValue: 'palette.radius.xl', options: [
|
|
165
|
+
{ value: 'palette.radius.none', label: 'None' },
|
|
166
|
+
{ value: 'palette.radius.sm', label: 'Small' },
|
|
167
|
+
{ value: 'palette.radius.md', label: 'Medium' },
|
|
168
|
+
{ value: 'palette.radius.lg', label: 'Large' },
|
|
169
|
+
{ value: 'palette.radius.xl', label: 'Extra Large' },
|
|
170
|
+
] },
|
|
171
|
+
{ id: 'style-panel-shadow', label: 'Panel Shadow', type: 'select', path: 'theme.components.panel.shadow', defaultValue: 'palette.shadows.xl', options: [
|
|
172
|
+
{ value: 'palette.shadows.none', label: 'None' },
|
|
173
|
+
{ value: 'palette.shadows.sm', label: 'Small' },
|
|
174
|
+
{ value: 'palette.shadows.md', label: 'Medium' },
|
|
175
|
+
{ value: 'palette.shadows.lg', label: 'Large' },
|
|
176
|
+
{ value: 'palette.shadows.xl', label: 'Extra Large' },
|
|
177
|
+
] },
|
|
178
|
+
{ id: 'style-msg-user-radius', label: 'User Message Radius', type: 'select', path: 'theme.components.message.user.borderRadius', defaultValue: 'palette.radius.lg', options: [
|
|
179
|
+
{ value: 'palette.radius.none', label: 'None' },
|
|
180
|
+
{ value: 'palette.radius.sm', label: 'Small' },
|
|
181
|
+
{ value: 'palette.radius.md', label: 'Medium' },
|
|
182
|
+
{ value: 'palette.radius.lg', label: 'Large' },
|
|
183
|
+
{ value: 'palette.radius.xl', label: 'Extra Large' },
|
|
184
|
+
] },
|
|
185
|
+
{ id: 'style-msg-assistant-radius', label: 'Assistant Message Radius', type: 'select', path: 'theme.components.message.assistant.borderRadius', defaultValue: 'palette.radius.lg', options: [
|
|
186
|
+
{ value: 'palette.radius.none', label: 'None' },
|
|
187
|
+
{ value: 'palette.radius.sm', label: 'Small' },
|
|
188
|
+
{ value: 'palette.radius.md', label: 'Medium' },
|
|
189
|
+
{ value: 'palette.radius.lg', label: 'Large' },
|
|
190
|
+
{ value: 'palette.radius.xl', label: 'Extra Large' },
|
|
191
|
+
] },
|
|
192
|
+
],
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const STYLE_SECTIONS: SectionDef[] = [
|
|
196
|
+
brandColorsSectionDef,
|
|
197
|
+
chatColorsSectionDef,
|
|
198
|
+
launcherStyleSectionDef,
|
|
199
|
+
typographySectionDef,
|
|
200
|
+
themeModeSectionDef,
|
|
201
|
+
shapeSectionDef,
|
|
202
|
+
shadowsSectionDef,
|
|
203
|
+
widgetStyleSectionDef,
|
|
204
|
+
];
|
|
205
|
+
|
|
206
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
207
|
+
// COLORS & STYLE TAB — palette scales, semantic tokens
|
|
208
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
209
|
+
|
|
210
|
+
function buildPaletteSectionDef(): SectionDef {
|
|
211
|
+
const fields = COLOR_FAMILIES.map(family => ({
|
|
212
|
+
id: `palette-${family}`,
|
|
213
|
+
label: `${family.charAt(0).toUpperCase() + family.slice(1)}`,
|
|
214
|
+
description: `${family} color palette (edit shade 500, auto-generate scale)`,
|
|
215
|
+
type: 'color-scale' as const,
|
|
216
|
+
path: `theme.palette.colors.${family}`,
|
|
217
|
+
colorScale: { colorFamily: family },
|
|
218
|
+
}));
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
id: 'brand-palette',
|
|
222
|
+
title: 'Brand Palette',
|
|
223
|
+
description: 'Define your color palette. Edit the base color (500) to auto-generate the full scale.',
|
|
224
|
+
collapsed: false,
|
|
225
|
+
fields,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const semanticColorsSectionDef: SectionDef = {
|
|
230
|
+
id: 'semantic-colors',
|
|
231
|
+
title: 'Semantic Colors',
|
|
232
|
+
description: 'Map intents to palette colors.',
|
|
233
|
+
collapsed: true,
|
|
234
|
+
fields: [
|
|
235
|
+
{ id: 'sem-primary', label: 'Primary', description: 'Main brand/action color', type: 'token-ref', path: 'theme.semantic.colors.primary', defaultValue: 'palette.colors.primary.500', tokenRef: { tokenType: 'color' } },
|
|
236
|
+
{ id: 'sem-secondary', label: 'Secondary', description: 'Secondary actions', type: 'token-ref', path: 'theme.semantic.colors.secondary', defaultValue: 'palette.colors.gray.500', tokenRef: { tokenType: 'color' } },
|
|
237
|
+
{ id: 'sem-accent', label: 'Accent', description: 'Accent/highlight color', type: 'token-ref', path: 'theme.semantic.colors.accent', defaultValue: 'palette.colors.primary.600', tokenRef: { tokenType: 'color' } },
|
|
238
|
+
{ id: 'sem-surface', label: 'Surface', description: 'Primary surface background', type: 'token-ref', path: 'theme.semantic.colors.surface', defaultValue: 'palette.colors.gray.50', tokenRef: { tokenType: 'color' } },
|
|
239
|
+
{ id: 'sem-background', label: 'Background', description: 'Page/widget background', type: 'token-ref', path: 'theme.semantic.colors.background', defaultValue: 'palette.colors.gray.50', tokenRef: { tokenType: 'color' } },
|
|
240
|
+
{ id: 'sem-container', label: 'Container', description: 'Container/card background', type: 'token-ref', path: 'theme.semantic.colors.container', defaultValue: 'palette.colors.gray.100', tokenRef: { tokenType: 'color' } },
|
|
241
|
+
{ id: 'sem-text', label: 'Text', description: 'Primary text color', type: 'token-ref', path: 'theme.semantic.colors.text', defaultValue: 'palette.colors.gray.900', tokenRef: { tokenType: 'color' } },
|
|
242
|
+
{ id: 'sem-text-muted', label: 'Text Muted', description: 'Secondary/muted text', type: 'token-ref', path: 'theme.semantic.colors.textMuted', defaultValue: 'palette.colors.gray.500', tokenRef: { tokenType: 'color' } },
|
|
243
|
+
{ id: 'sem-text-inverse', label: 'Text Inverse', description: 'Text on dark backgrounds', type: 'token-ref', path: 'theme.semantic.colors.textInverse', defaultValue: 'palette.colors.gray.50', tokenRef: { tokenType: 'color' } },
|
|
244
|
+
{ id: 'sem-border', label: 'Border', description: 'Default border color', type: 'token-ref', path: 'theme.semantic.colors.border', defaultValue: 'palette.colors.gray.200', tokenRef: { tokenType: 'color' } },
|
|
245
|
+
{ id: 'sem-divider', label: 'Divider', description: 'Divider/separator color', type: 'token-ref', path: 'theme.semantic.colors.divider', defaultValue: 'palette.colors.gray.200', tokenRef: { tokenType: 'color' } },
|
|
246
|
+
{ id: 'sem-interactive-default', label: 'Interactive Default', type: 'token-ref', path: 'theme.semantic.colors.interactive.default', defaultValue: 'palette.colors.primary.500', tokenRef: { tokenType: 'color' } },
|
|
247
|
+
{ id: 'sem-interactive-hover', label: 'Interactive Hover', type: 'token-ref', path: 'theme.semantic.colors.interactive.hover', defaultValue: 'palette.colors.primary.600', tokenRef: { tokenType: 'color' } },
|
|
248
|
+
{ id: 'sem-interactive-focus', label: 'Interactive Focus', type: 'token-ref', path: 'theme.semantic.colors.interactive.focus', defaultValue: 'palette.colors.primary.700', tokenRef: { tokenType: 'color' } },
|
|
249
|
+
{ id: 'sem-interactive-active', label: 'Interactive Active', type: 'token-ref', path: 'theme.semantic.colors.interactive.active', defaultValue: 'palette.colors.primary.800', tokenRef: { tokenType: 'color' } },
|
|
250
|
+
{ id: 'sem-interactive-disabled', label: 'Interactive Disabled', type: 'token-ref', path: 'theme.semantic.colors.interactive.disabled', defaultValue: 'palette.colors.gray.300', tokenRef: { tokenType: 'color' } },
|
|
251
|
+
{ id: 'sem-feedback-success', label: 'Success', type: 'token-ref', path: 'theme.semantic.colors.feedback.success', defaultValue: 'palette.colors.success.500', tokenRef: { tokenType: 'color' } },
|
|
252
|
+
{ id: 'sem-feedback-warning', label: 'Warning', type: 'token-ref', path: 'theme.semantic.colors.feedback.warning', defaultValue: 'palette.colors.warning.500', tokenRef: { tokenType: 'color' } },
|
|
253
|
+
{ id: 'sem-feedback-error', label: 'Error', type: 'token-ref', path: 'theme.semantic.colors.feedback.error', defaultValue: 'palette.colors.error.500', tokenRef: { tokenType: 'color' } },
|
|
254
|
+
{ id: 'sem-feedback-info', label: 'Info', type: 'token-ref', path: 'theme.semantic.colors.feedback.info', defaultValue: 'palette.colors.primary.500', tokenRef: { tokenType: 'color' } },
|
|
255
|
+
],
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
export const PALETTE_SECTION: SectionDef = buildPaletteSectionDef();
|
|
259
|
+
export const SEMANTIC_COLORS_SECTION: SectionDef = semanticColorsSectionDef;
|
|
260
|
+
|
|
261
|
+
export const COLORS_SECTIONS: SectionDef[] = [
|
|
262
|
+
buildPaletteSectionDef(),
|
|
263
|
+
semanticColorsSectionDef,
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
267
|
+
// DESIGN SYSTEM TAB — component shapes, colors, layout
|
|
268
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
269
|
+
|
|
270
|
+
const panelLayoutSectionDef: SectionDef = {
|
|
271
|
+
id: 'comp-panel',
|
|
272
|
+
title: 'Panel',
|
|
273
|
+
collapsed: false,
|
|
274
|
+
fields: [
|
|
275
|
+
{ id: 'panel-width', label: 'Width', type: 'text', path: 'theme.components.panel.width', defaultValue: 'min(400px, calc(100vw - 24px))' },
|
|
276
|
+
{ id: 'panel-max-width', label: 'Max Width', type: 'text', path: 'theme.components.panel.maxWidth', defaultValue: '400px' },
|
|
277
|
+
{ id: 'panel-height', label: 'Height', type: 'text', path: 'theme.components.panel.height', defaultValue: '600px' },
|
|
278
|
+
{ id: 'panel-max-height', label: 'Max Height', type: 'text', path: 'theme.components.panel.maxHeight', defaultValue: 'calc(100vh - 80px)' },
|
|
279
|
+
{ id: 'panel-border-radius', label: 'Border Radius', type: 'select', path: 'theme.components.panel.borderRadius', defaultValue: 'palette.radius.xl', options: [
|
|
280
|
+
{ value: 'palette.radius.none', label: 'None' },
|
|
281
|
+
{ value: 'palette.radius.sm', label: 'Small' },
|
|
282
|
+
{ value: 'palette.radius.md', label: 'Medium' },
|
|
283
|
+
{ value: 'palette.radius.lg', label: 'Large' },
|
|
284
|
+
{ value: 'palette.radius.xl', label: 'Extra Large' },
|
|
285
|
+
] },
|
|
286
|
+
{ id: 'panel-shadow', label: 'Shadow', type: 'select', path: 'theme.components.panel.shadow', defaultValue: 'palette.shadows.xl', options: [
|
|
287
|
+
{ value: 'palette.shadows.none', label: 'None' },
|
|
288
|
+
{ value: 'palette.shadows.sm', label: 'Small' },
|
|
289
|
+
{ value: 'palette.shadows.md', label: 'Medium' },
|
|
290
|
+
{ value: 'palette.shadows.lg', label: 'Large' },
|
|
291
|
+
{ value: 'palette.shadows.xl', label: 'Extra Large' },
|
|
292
|
+
] },
|
|
293
|
+
],
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const launcherLayoutSectionDef: SectionDef = {
|
|
297
|
+
id: 'comp-launcher',
|
|
298
|
+
title: 'Launcher',
|
|
299
|
+
collapsed: true,
|
|
300
|
+
fields: [
|
|
301
|
+
{ id: 'launcher-size', label: 'Size', type: 'slider', path: 'theme.components.launcher.size', defaultValue: '60px', slider: { min: 32, max: 80, step: 2 } },
|
|
302
|
+
{ id: 'launcher-icon-size', label: 'Icon Size', type: 'slider', path: 'theme.components.launcher.iconSize', defaultValue: '28px', slider: { min: 16, max: 48, step: 2 } },
|
|
303
|
+
{ id: 'launcher-border-radius', label: 'Border Radius', type: 'select', path: 'theme.components.launcher.borderRadius', defaultValue: 'palette.radius.full', options: [
|
|
304
|
+
{ value: 'palette.radius.md', label: 'Medium' },
|
|
305
|
+
{ value: 'palette.radius.lg', label: 'Large' },
|
|
306
|
+
{ value: 'palette.radius.xl', label: 'Extra Large' },
|
|
307
|
+
{ value: 'palette.radius.full', label: 'Full (Circle)' },
|
|
308
|
+
] },
|
|
309
|
+
{ id: 'launcher-shadow', label: 'Shadow', type: 'select', path: 'theme.components.launcher.shadow', defaultValue: 'palette.shadows.lg', options: [
|
|
310
|
+
{ value: 'palette.shadows.none', label: 'None' },
|
|
311
|
+
{ value: 'palette.shadows.sm', label: 'Small' },
|
|
312
|
+
{ value: 'palette.shadows.md', label: 'Medium' },
|
|
313
|
+
{ value: 'palette.shadows.lg', label: 'Large' },
|
|
314
|
+
{ value: 'palette.shadows.xl', label: 'Extra Large' },
|
|
315
|
+
] },
|
|
316
|
+
],
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const messageShapeSectionDef: SectionDef = {
|
|
320
|
+
id: 'comp-message-shape',
|
|
321
|
+
title: 'Message Shape',
|
|
322
|
+
collapsed: true,
|
|
323
|
+
fields: [
|
|
324
|
+
{ id: 'msg-user-radius', label: 'User Bubble Radius', type: 'select', path: 'theme.components.message.user.borderRadius', defaultValue: 'palette.radius.lg', options: [
|
|
325
|
+
{ value: 'palette.radius.none', label: 'None' },
|
|
326
|
+
{ value: 'palette.radius.sm', label: 'Small' },
|
|
327
|
+
{ value: 'palette.radius.md', label: 'Medium' },
|
|
328
|
+
{ value: 'palette.radius.lg', label: 'Large' },
|
|
329
|
+
{ value: 'palette.radius.xl', label: 'Extra Large' },
|
|
330
|
+
] },
|
|
331
|
+
{ id: 'msg-assistant-radius', label: 'Assistant Bubble Radius', type: 'select', path: 'theme.components.message.assistant.borderRadius', defaultValue: 'palette.radius.lg', options: [
|
|
332
|
+
{ value: 'palette.radius.none', label: 'None' },
|
|
333
|
+
{ value: 'palette.radius.sm', label: 'Small' },
|
|
334
|
+
{ value: 'palette.radius.md', label: 'Medium' },
|
|
335
|
+
{ value: 'palette.radius.lg', label: 'Large' },
|
|
336
|
+
{ value: 'palette.radius.xl', label: 'Extra Large' },
|
|
337
|
+
] },
|
|
338
|
+
],
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const inputShapeSectionDef: SectionDef = {
|
|
342
|
+
id: 'comp-input-shape',
|
|
343
|
+
title: 'Input Shape',
|
|
344
|
+
collapsed: true,
|
|
345
|
+
fields: [
|
|
346
|
+
{ id: 'input-radius', label: 'Border Radius', type: 'select', path: 'theme.components.input.borderRadius', defaultValue: 'palette.radius.lg', options: [
|
|
347
|
+
{ value: 'palette.radius.none', label: 'None' },
|
|
348
|
+
{ value: 'palette.radius.sm', label: 'Small' },
|
|
349
|
+
{ value: 'palette.radius.md', label: 'Medium' },
|
|
350
|
+
{ value: 'palette.radius.lg', label: 'Large' },
|
|
351
|
+
{ value: 'palette.radius.xl', label: 'Extra Large' },
|
|
352
|
+
] },
|
|
353
|
+
],
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
const buttonShapeSectionDef: SectionDef = {
|
|
357
|
+
id: 'comp-button-shape',
|
|
358
|
+
title: 'Button Shape',
|
|
359
|
+
collapsed: true,
|
|
360
|
+
fields: [
|
|
361
|
+
{ id: 'btn-primary-radius', label: 'Primary Radius', type: 'select', path: 'theme.components.button.primary.borderRadius', defaultValue: 'palette.radius.lg', options: [
|
|
362
|
+
{ value: 'palette.radius.sm', label: 'Small' },
|
|
363
|
+
{ value: 'palette.radius.md', label: 'Medium' },
|
|
364
|
+
{ value: 'palette.radius.lg', label: 'Large' },
|
|
365
|
+
{ value: 'palette.radius.full', label: 'Full' },
|
|
366
|
+
] },
|
|
367
|
+
],
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
const headerColorsSectionDef: SectionDef = {
|
|
371
|
+
id: 'comp-header-colors',
|
|
372
|
+
title: 'Header Colors',
|
|
373
|
+
collapsed: true,
|
|
374
|
+
fields: [
|
|
375
|
+
{ id: 'header-bg', label: 'Background', type: 'token-ref', path: 'theme.components.header.background', defaultValue: 'semantic.colors.surface', tokenRef: { tokenType: 'color' } },
|
|
376
|
+
{ id: 'header-icon-bg', label: 'Icon background', type: 'token-ref', path: 'theme.components.header.iconBackground', defaultValue: 'semantic.colors.primary', tokenRef: { tokenType: 'color' } },
|
|
377
|
+
{ id: 'header-icon-fg', label: 'Icon color', type: 'token-ref', path: 'theme.components.header.iconForeground', defaultValue: 'semantic.colors.textInverse', tokenRef: { tokenType: 'color' } },
|
|
378
|
+
{ id: 'header-title-fg', label: 'Title color', type: 'token-ref', path: 'theme.components.header.titleForeground', defaultValue: 'semantic.colors.primary', tokenRef: { tokenType: 'color' } },
|
|
379
|
+
{ id: 'header-subtitle-fg', label: 'Subtitle color', type: 'token-ref', path: 'theme.components.header.subtitleForeground', defaultValue: 'semantic.colors.textMuted', tokenRef: { tokenType: 'color' } },
|
|
380
|
+
{ id: 'header-action-icons-fg', label: 'Clear / close icons', type: 'token-ref', path: 'theme.components.header.actionIconForeground', defaultValue: 'semantic.colors.textMuted', tokenRef: { tokenType: 'color' } },
|
|
381
|
+
{ id: 'header-border', label: 'Border', type: 'token-ref', path: 'theme.components.header.border', defaultValue: 'semantic.colors.border', tokenRef: { tokenType: 'color' } },
|
|
382
|
+
],
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const messageColorsSectionDef: SectionDef = {
|
|
386
|
+
id: 'comp-message-colors',
|
|
387
|
+
title: 'Message Colors',
|
|
388
|
+
collapsed: true,
|
|
389
|
+
fields: [
|
|
390
|
+
{ id: 'msg-user-bg', label: 'User Bubble Background', type: 'token-ref', path: 'theme.components.message.user.background', defaultValue: 'semantic.colors.primary', tokenRef: { tokenType: 'color' } },
|
|
391
|
+
{ id: 'msg-user-text', label: 'User Bubble Text', type: 'token-ref', path: 'theme.components.message.user.text', defaultValue: 'semantic.colors.textInverse', tokenRef: { tokenType: 'color' } },
|
|
392
|
+
{ id: 'msg-assistant-bg', label: 'Assistant Bubble Background', type: 'token-ref', path: 'theme.components.message.assistant.background', defaultValue: 'semantic.colors.container', tokenRef: { tokenType: 'color' } },
|
|
393
|
+
{ id: 'msg-assistant-text', label: 'Assistant Bubble Text', type: 'token-ref', path: 'theme.components.message.assistant.text', defaultValue: 'semantic.colors.text', tokenRef: { tokenType: 'color' } },
|
|
394
|
+
],
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
const inputColorsSectionDef: SectionDef = {
|
|
398
|
+
id: 'comp-input-colors',
|
|
399
|
+
title: 'Input Colors',
|
|
400
|
+
collapsed: true,
|
|
401
|
+
fields: [
|
|
402
|
+
{ id: 'input-bg', label: 'Background', type: 'token-ref', path: 'theme.components.input.background', defaultValue: 'semantic.colors.surface', tokenRef: { tokenType: 'color' } },
|
|
403
|
+
{ id: 'input-placeholder', label: 'Placeholder Color', type: 'token-ref', path: 'theme.components.input.placeholder', defaultValue: 'semantic.colors.textMuted', tokenRef: { tokenType: 'color' } },
|
|
404
|
+
{ id: 'input-focus-border', label: 'Focus Border', type: 'token-ref', path: 'theme.components.input.focus.border', defaultValue: 'semantic.colors.interactive.focus', tokenRef: { tokenType: 'color' } },
|
|
405
|
+
{ id: 'input-focus-ring', label: 'Focus Ring', type: 'token-ref', path: 'theme.components.input.focus.ring', defaultValue: 'semantic.colors.interactive.focus', tokenRef: { tokenType: 'color' } },
|
|
406
|
+
],
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const buttonColorsSectionDef: SectionDef = {
|
|
410
|
+
id: 'comp-button-colors',
|
|
411
|
+
title: 'Button Colors',
|
|
412
|
+
collapsed: true,
|
|
413
|
+
fields: [
|
|
414
|
+
{ id: 'btn-primary-bg', label: 'Primary Background', type: 'token-ref', path: 'theme.components.button.primary.background', defaultValue: 'semantic.colors.primary', tokenRef: { tokenType: 'color' } },
|
|
415
|
+
{ id: 'btn-primary-fg', label: 'Primary Foreground', type: 'token-ref', path: 'theme.components.button.primary.foreground', defaultValue: 'semantic.colors.textInverse', tokenRef: { tokenType: 'color' } },
|
|
416
|
+
{ id: 'btn-secondary-bg', label: 'Secondary Background', type: 'token-ref', path: 'theme.components.button.secondary.background', defaultValue: 'semantic.colors.surface', tokenRef: { tokenType: 'color' } },
|
|
417
|
+
{ id: 'btn-secondary-fg', label: 'Secondary Foreground', type: 'token-ref', path: 'theme.components.button.secondary.foreground', defaultValue: 'semantic.colors.text', tokenRef: { tokenType: 'color' } },
|
|
418
|
+
{ id: 'btn-ghost-bg', label: 'Ghost Background', type: 'color', path: 'theme.components.button.ghost.background', defaultValue: 'transparent' },
|
|
419
|
+
{ id: 'btn-ghost-fg', label: 'Ghost Foreground', type: 'token-ref', path: 'theme.components.button.ghost.foreground', defaultValue: 'semantic.colors.text', tokenRef: { tokenType: 'color' } },
|
|
420
|
+
],
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
/** Shared shape sections (not scoped to light/dark) */
|
|
424
|
+
export const COMPONENT_SHAPE_SECTIONS: SectionDef[] = [
|
|
425
|
+
panelLayoutSectionDef,
|
|
426
|
+
launcherLayoutSectionDef,
|
|
427
|
+
messageShapeSectionDef,
|
|
428
|
+
inputShapeSectionDef,
|
|
429
|
+
buttonShapeSectionDef,
|
|
430
|
+
];
|
|
431
|
+
|
|
432
|
+
/** Component color sections (can be scoped for light/dark) */
|
|
433
|
+
export const COMPONENT_COLOR_SECTIONS: SectionDef[] = [
|
|
434
|
+
headerColorsSectionDef,
|
|
435
|
+
messageColorsSectionDef,
|
|
436
|
+
inputColorsSectionDef,
|
|
437
|
+
buttonColorsSectionDef,
|
|
438
|
+
];
|
|
439
|
+
|
|
440
|
+
export const COMPONENTS_SECTIONS: SectionDef[] = [
|
|
441
|
+
...COMPONENT_SHAPE_SECTIONS,
|
|
442
|
+
...COMPONENT_COLOR_SECTIONS,
|
|
443
|
+
];
|
|
444
|
+
|
|
445
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
446
|
+
// CONFIGURE TAB — content, layout, widget, features, developer
|
|
447
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
448
|
+
|
|
449
|
+
const MB = 1024 * 1024;
|
|
450
|
+
const DEFAULT_SUGGESTION_CHIPS = [
|
|
451
|
+
'What can you help me with?',
|
|
452
|
+
'Tell me about your features',
|
|
453
|
+
'How does this work?',
|
|
454
|
+
];
|
|
455
|
+
|
|
456
|
+
const ATTACHMENT_TYPE_PRESETS: Record<string, string[]> = {
|
|
457
|
+
images: ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml', 'image/bmp'],
|
|
458
|
+
'images-pdf': ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml', 'image/bmp', 'application/pdf'],
|
|
459
|
+
'images-text-pdf': ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml', 'image/bmp', 'application/pdf', 'text/plain', 'text/markdown', 'text/csv', 'application/json'],
|
|
460
|
+
all: ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml', 'image/bmp', 'application/pdf', 'text/plain', 'text/markdown', 'text/csv', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/json'],
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
function parseAttachmentMaxFileSize(value: unknown): number {
|
|
464
|
+
return Number(value) * MB;
|
|
465
|
+
}
|
|
466
|
+
function formatAttachmentMaxFileSize(value: unknown): string {
|
|
467
|
+
const numeric = Number(value);
|
|
468
|
+
if (!Number.isFinite(numeric)) return '10';
|
|
469
|
+
return numeric > 1024 ? String(Math.round(numeric / MB)) : String(numeric);
|
|
470
|
+
}
|
|
471
|
+
function parseAttachmentAllowedTypes(value: unknown): string[] {
|
|
472
|
+
return ATTACHMENT_TYPE_PRESETS[String(value)] ?? ATTACHMENT_TYPE_PRESETS.images;
|
|
473
|
+
}
|
|
474
|
+
function formatAttachmentAllowedTypes(value: unknown): string {
|
|
475
|
+
const allowedTypes = Array.isArray(value) ? value : ATTACHMENT_TYPE_PRESETS.images;
|
|
476
|
+
const normalized = [...new Set(allowedTypes)].sort();
|
|
477
|
+
for (const [presetKey, presetTypes] of Object.entries(ATTACHMENT_TYPE_PRESETS)) {
|
|
478
|
+
const sortedPreset = [...presetTypes].sort();
|
|
479
|
+
if (normalized.length === sortedPreset.length && normalized.every((type, index) => type === sortedPreset[index])) {
|
|
480
|
+
return presetKey;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (normalized.some(type => type.startsWith('application/vnd') || type === 'application/msword')) return 'all';
|
|
484
|
+
if (normalized.some(type => type === 'text/plain' || type === 'text/markdown' || type === 'text/csv')) return 'images-text-pdf';
|
|
485
|
+
if (normalized.includes('application/pdf')) return 'images-pdf';
|
|
486
|
+
return 'images';
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const copySectionDef: SectionDef = {
|
|
490
|
+
id: 'copy', title: 'Content & Copy', collapsed: false,
|
|
491
|
+
fields: [
|
|
492
|
+
{ id: 'copy-show-welcome-card', label: 'Show Welcome Card', type: 'toggle', path: 'copy.showWelcomeCard', defaultValue: true },
|
|
493
|
+
{ id: 'copy-welcome-title', label: 'Welcome Title', type: 'text', path: 'copy.welcomeTitle', defaultValue: 'Hello 👋' },
|
|
494
|
+
{ id: 'copy-welcome-subtitle', label: 'Welcome Subtitle', type: 'text', path: 'copy.welcomeSubtitle', defaultValue: 'Ask anything about your account or products.' },
|
|
495
|
+
{ id: 'copy-placeholder', label: 'Input Placeholder', type: 'text', path: 'copy.inputPlaceholder', defaultValue: 'Type your message…' },
|
|
496
|
+
{ id: 'copy-send-label', label: 'Send Button Label', type: 'text', path: 'copy.sendButtonLabel', defaultValue: 'Send' },
|
|
497
|
+
],
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
const suggestionsSectionDef: SectionDef = {
|
|
501
|
+
id: 'suggestions', title: 'Suggestion Chips', description: 'Configure chip content and styling.', collapsed: true,
|
|
502
|
+
fields: [
|
|
503
|
+
{ id: 'suggestions-list', label: 'Suggestions', description: 'Add, edit, and remove chips directly.', type: 'chip-list', path: 'suggestionChips', defaultValue: DEFAULT_SUGGESTION_CHIPS },
|
|
504
|
+
],
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
const generalLayoutSectionDef: SectionDef = {
|
|
508
|
+
id: 'general-layout', title: 'Layout Basics', collapsed: true,
|
|
509
|
+
fields: [
|
|
510
|
+
{ id: 'layout-show-header', label: 'Show Header', type: 'toggle', path: 'layout.showHeader', defaultValue: true },
|
|
511
|
+
{ id: 'layout-show-footer', label: 'Show Footer', type: 'toggle', path: 'layout.showFooter', defaultValue: true },
|
|
512
|
+
{ id: 'layout-content-max-width', label: 'Content Max Width', description: 'Max width for messages + composer', type: 'text', path: 'layout.contentMaxWidth', defaultValue: '' },
|
|
513
|
+
],
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
const headerLayoutSectionDef: SectionDef = {
|
|
517
|
+
id: 'header-layout', title: 'Header', collapsed: true,
|
|
518
|
+
fields: [
|
|
519
|
+
{ id: 'layout-header', label: 'Header Layout', type: 'select', path: 'layout.header.layout', defaultValue: 'default', options: [{ value: 'default', label: 'Default' }, { value: 'minimal', label: 'Minimal' }] },
|
|
520
|
+
{ id: 'layout-show-icon', label: 'Show Header Icon', type: 'toggle', path: 'layout.header.showIcon', defaultValue: true },
|
|
521
|
+
{ id: 'layout-show-title', label: 'Show Header Title', type: 'toggle', path: 'layout.header.showTitle', defaultValue: true },
|
|
522
|
+
{ id: 'layout-show-subtitle', label: 'Show Header Subtitle', type: 'toggle', path: 'layout.header.showSubtitle', defaultValue: true },
|
|
523
|
+
{ id: 'layout-show-close', label: 'Show Close Button', type: 'toggle', path: 'layout.header.showCloseButton', defaultValue: true },
|
|
524
|
+
{ id: 'layout-show-clear', label: 'Show Clear Chat', type: 'toggle', path: 'layout.header.showClearChat', defaultValue: true },
|
|
525
|
+
],
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
const messagesLayoutSectionDef: SectionDef = {
|
|
529
|
+
id: 'messages-layout', title: 'Messages', collapsed: true,
|
|
530
|
+
fields: [
|
|
531
|
+
{ id: 'layout-messages', label: 'Messages Layout', type: 'select', path: 'layout.messages.layout', defaultValue: 'bubble', options: [{ value: 'bubble', label: 'Bubble' }, { value: 'flat', label: 'Flat' }, { value: 'minimal', label: 'Minimal' }] },
|
|
532
|
+
{ id: 'layout-group', label: 'Group Consecutive', type: 'toggle', path: 'layout.messages.groupConsecutive', defaultValue: false },
|
|
533
|
+
{ id: 'layout-avatar-show', label: 'Show Avatars', type: 'toggle', path: 'layout.messages.avatar.show', defaultValue: false },
|
|
534
|
+
{ id: 'layout-avatar-pos', label: 'Avatar Position', type: 'select', path: 'layout.messages.avatar.position', defaultValue: 'left', options: [{ value: 'left', label: 'Left' }, { value: 'right', label: 'Right' }] },
|
|
535
|
+
{ id: 'layout-avatar-user', label: 'User Avatar URL', type: 'text', path: 'layout.messages.avatar.userAvatar', defaultValue: '' },
|
|
536
|
+
{ id: 'layout-avatar-assistant', label: 'Assistant Avatar URL', type: 'text', path: 'layout.messages.avatar.assistantAvatar', defaultValue: '' },
|
|
537
|
+
{ id: 'layout-timestamp-show', label: 'Show Timestamps', type: 'toggle', path: 'layout.messages.timestamp.show', defaultValue: false },
|
|
538
|
+
{ id: 'layout-timestamp-pos', label: 'Timestamp Position', type: 'select', path: 'layout.messages.timestamp.position', defaultValue: 'inline', options: [{ value: 'inline', label: 'Inline' }, { value: 'below', label: 'Below' }] },
|
|
539
|
+
],
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
const messageActionsSectionDef: SectionDef = {
|
|
543
|
+
id: 'message-actions', title: 'Message Actions', collapsed: true,
|
|
544
|
+
fields: [
|
|
545
|
+
{ id: 'msg-actions-enabled', label: 'Enabled', type: 'toggle', path: 'messageActions.enabled', defaultValue: true },
|
|
546
|
+
{ id: 'msg-actions-copy', label: 'Show Copy', type: 'toggle', path: 'messageActions.showCopy', defaultValue: true },
|
|
547
|
+
{ id: 'msg-actions-upvote', label: 'Show Upvote', type: 'toggle', path: 'messageActions.showUpvote', defaultValue: true },
|
|
548
|
+
{ id: 'msg-actions-downvote', label: 'Show Downvote', type: 'toggle', path: 'messageActions.showDownvote', defaultValue: true },
|
|
549
|
+
{ id: 'msg-actions-visibility', label: 'Visibility', type: 'select', path: 'messageActions.visibility', defaultValue: 'hover', options: [{ value: 'hover', label: 'On Hover' }, { value: 'always', label: 'Always Visible' }] },
|
|
550
|
+
{ id: 'msg-actions-align', label: 'Alignment', type: 'select', path: 'messageActions.align', defaultValue: 'right', options: [{ value: 'left', label: 'Left' }, { value: 'right', label: 'Right' }] },
|
|
551
|
+
{ id: 'msg-actions-layout', label: 'Layout', type: 'select', path: 'messageActions.layout', defaultValue: 'pill-inside', options: [{ value: 'pill-inside', label: 'Pill' }, { value: 'row-inside', label: 'Row' }] },
|
|
552
|
+
],
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
const launcherBasicsSectionDef: SectionDef = {
|
|
556
|
+
id: 'launcher-basics', title: 'Launcher', collapsed: true,
|
|
557
|
+
fields: [
|
|
558
|
+
{ id: 'launch-enabled', label: 'Enabled', type: 'toggle', path: 'launcher.enabled', defaultValue: true },
|
|
559
|
+
{ id: 'launch-mount-mode', label: 'Mount Mode', type: 'select', path: 'launcher.mountMode', defaultValue: 'floating', options: [{ value: 'floating', label: 'Floating' }, { value: 'docked', label: 'Docked' }] },
|
|
560
|
+
{ id: 'launch-position', label: 'Position', type: 'select', path: 'launcher.position', defaultValue: 'bottom-right', options: [{ value: 'bottom-right', label: 'Bottom Right' }, { value: 'bottom-left', label: 'Bottom Left' }, { value: 'top-right', label: 'Top Right' }, { value: 'top-left', label: 'Top Left' }] },
|
|
561
|
+
{ id: 'launch-width', label: 'Width', type: 'text', path: 'launcher.width', defaultValue: 'min(400px, calc(100vw - 24px))' },
|
|
562
|
+
{ id: 'launch-auto-expand', label: 'Auto Expand', type: 'toggle', path: 'launcher.autoExpand', defaultValue: false },
|
|
563
|
+
{ id: 'launch-title', label: 'Title', type: 'text', path: 'launcher.title', defaultValue: 'Chat Assistant' },
|
|
564
|
+
{ id: 'launch-subtitle', label: 'Subtitle', type: 'text', path: 'launcher.subtitle', defaultValue: 'Here to help you get answers fast' },
|
|
565
|
+
],
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
const launcherAdvancedSectionDef: SectionDef = {
|
|
569
|
+
id: 'launcher-advanced', title: 'Launcher Advanced', collapsed: true,
|
|
570
|
+
fields: [
|
|
571
|
+
{ id: 'launch-dock-side', label: 'Dock Side', type: 'select', path: 'launcher.dock.side', defaultValue: 'right', options: [{ value: 'right', label: 'Right' }, { value: 'left', label: 'Left' }] },
|
|
572
|
+
{ id: 'launch-dock-width', label: 'Dock Width', type: 'text', path: 'launcher.dock.width', defaultValue: '420px' },
|
|
573
|
+
{ id: 'launch-dock-animate', label: 'Dock Animate', type: 'toggle', path: 'launcher.dock.animate', defaultValue: true },
|
|
574
|
+
{ id: 'launch-dock-reveal', label: 'Dock Reveal', type: 'select', path: 'launcher.dock.reveal', defaultValue: 'resize', options: [{ value: 'resize', label: 'Resize' }, { value: 'overlay', label: 'Overlay' }, { value: 'push', label: 'Push' }, { value: 'emerge', label: 'Emerge' }] },
|
|
575
|
+
{ id: 'launch-text-hidden', label: 'Hide Text', type: 'toggle', path: 'launcher.textHidden', defaultValue: false },
|
|
576
|
+
{ id: 'launch-icon-text', label: 'Agent Icon Text', type: 'text', path: 'launcher.agentIconText', defaultValue: '💬' },
|
|
577
|
+
{ id: 'launch-icon-name', label: 'Agent Icon Name (Lucide)', type: 'text', path: 'launcher.agentIconName', defaultValue: 'bot' },
|
|
578
|
+
{ id: 'launch-icon-hidden', label: 'Hide Agent Icon', type: 'toggle', path: 'launcher.agentIconHidden', defaultValue: false },
|
|
579
|
+
{ id: 'launch-icon-size', label: 'Agent Icon Size', type: 'slider', path: 'launcher.agentIconSize', defaultValue: '40px', slider: { min: 16, max: 72, step: 2 } },
|
|
580
|
+
{ id: 'launch-icon-url', label: 'Icon Image URL', description: 'Custom image URL (overrides emoji/lucide)', type: 'text', path: 'launcher.iconUrl', defaultValue: '' },
|
|
581
|
+
{ id: 'launch-header-icon-name', label: 'Header Icon Name (Lucide)', type: 'text', path: 'launcher.headerIconName', defaultValue: 'bot' },
|
|
582
|
+
{ id: 'launch-header-icon-size', label: 'Header Icon Size', type: 'slider', path: 'launcher.headerIconSize', defaultValue: '48px', slider: { min: 24, max: 80, step: 2 } },
|
|
583
|
+
{ id: 'launch-header-icon-hidden', label: 'Hide Header Icon', type: 'toggle', path: 'launcher.headerIconHidden', defaultValue: false },
|
|
584
|
+
{ id: 'launch-full-height', label: 'Full Height', type: 'toggle', path: 'launcher.fullHeight', defaultValue: false },
|
|
585
|
+
{ id: 'launch-sidebar', label: 'Sidebar Mode', type: 'toggle', path: 'launcher.sidebarMode', defaultValue: false },
|
|
586
|
+
{ id: 'launch-sidebar-width', label: 'Sidebar Width', type: 'text', path: 'launcher.sidebarWidth', defaultValue: '420px' },
|
|
587
|
+
{ id: 'launch-mobile-fullscreen', label: 'Mobile Fullscreen', description: 'Fullscreen on mobile devices', type: 'toggle', path: 'launcher.mobileFullscreen', defaultValue: true },
|
|
588
|
+
{ id: 'launch-mobile-breakpoint', label: 'Mobile Breakpoint (px)', type: 'text', path: 'launcher.mobileBreakpoint', defaultValue: 640, formatValue: (v: unknown) => String(v ?? 640), parseValue: (v: unknown) => Number(v) },
|
|
589
|
+
{ id: 'launch-height-offset', label: 'Height Offset (px)', type: 'text', path: 'launcher.heightOffset', defaultValue: 0, formatValue: (v: unknown) => String(v ?? 0), parseValue: (v: unknown) => Number(v) },
|
|
590
|
+
{ id: 'launch-collapsed-max-width', label: 'Collapsed Max Width', description: 'Max width of launcher pill when closed', type: 'text', path: 'launcher.collapsedMaxWidth', defaultValue: '' },
|
|
591
|
+
{ id: 'launch-cta-text', label: 'CTA Icon Text', type: 'text', path: 'launcher.callToActionIconText', defaultValue: '↗' },
|
|
592
|
+
{ id: 'launch-cta-name', label: 'CTA Icon Name', type: 'text', path: 'launcher.callToActionIconName', defaultValue: '' },
|
|
593
|
+
{ id: 'launch-cta-hidden', label: 'Hide CTA Icon', type: 'toggle', path: 'launcher.callToActionIconHidden', defaultValue: false },
|
|
594
|
+
{ id: 'launch-cta-size', label: 'CTA Icon Size', type: 'slider', path: 'launcher.callToActionIconSize', defaultValue: '32px', slider: { min: 16, max: 64, step: 2 } },
|
|
595
|
+
{ id: 'launch-cta-padding', label: 'CTA Icon Padding', type: 'slider', path: 'launcher.callToActionIconPadding', defaultValue: '5px', slider: { min: 0, max: 24, step: 1 } },
|
|
596
|
+
{ id: 'launch-cta-bg', label: 'CTA Icon Background', type: 'color', path: 'launcher.callToActionIconBackgroundColor', defaultValue: '' },
|
|
597
|
+
],
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
const sendButtonSectionDef: SectionDef = {
|
|
601
|
+
id: 'send-button', title: 'Send Button', collapsed: true,
|
|
602
|
+
fields: [
|
|
603
|
+
{ id: 'send-use-icon', label: 'Use Icon', type: 'toggle', path: 'sendButton.useIcon', defaultValue: false },
|
|
604
|
+
{ id: 'send-icon-text', label: 'Icon Text', type: 'text', path: 'sendButton.iconText', defaultValue: '↑' },
|
|
605
|
+
{ id: 'send-icon-name', label: 'Icon Name (Lucide)', type: 'text', path: 'sendButton.iconName', defaultValue: '' },
|
|
606
|
+
{ id: 'send-size', label: 'Size', type: 'slider', path: 'sendButton.size', defaultValue: '40px', slider: { min: 24, max: 64, step: 2 } },
|
|
607
|
+
{ id: 'send-border-width', label: 'Border Width', type: 'slider', path: 'sendButton.borderWidth', defaultValue: '0px', slider: { min: 0, max: 10, step: 1 } },
|
|
608
|
+
{ id: 'send-padding-x', label: 'Padding X', type: 'slider', path: 'sendButton.paddingX', defaultValue: '10px', slider: { min: 0, max: 32, step: 1 } },
|
|
609
|
+
{ id: 'send-padding-y', label: 'Padding Y', type: 'slider', path: 'sendButton.paddingY', defaultValue: '6px', slider: { min: 0, max: 32, step: 1 } },
|
|
610
|
+
{ id: 'send-show-tooltip', label: 'Show Tooltip', type: 'toggle', path: 'sendButton.showTooltip', defaultValue: false },
|
|
611
|
+
{ id: 'send-tooltip-text', label: 'Tooltip Text', type: 'text', path: 'sendButton.tooltipText', defaultValue: 'Send message' },
|
|
612
|
+
],
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
const closeButtonSectionDef: SectionDef = {
|
|
616
|
+
id: 'close-button', title: 'Close Button', collapsed: true,
|
|
617
|
+
fields: [
|
|
618
|
+
{ id: 'close-size', label: 'Size', type: 'slider', path: 'launcher.closeButtonSize', defaultValue: '32px', slider: { min: 16, max: 64, step: 1 } },
|
|
619
|
+
{ id: 'close-placement', label: 'Placement', type: 'select', path: 'launcher.closeButtonPlacement', defaultValue: 'inline', options: [{ value: 'inline', label: 'Inline' }, { value: 'top-right', label: 'Top Right' }] },
|
|
620
|
+
{ id: 'close-border-width', label: 'Border Width', type: 'slider', path: 'launcher.closeButtonBorderWidth', defaultValue: '0px', slider: { min: 0, max: 8, step: 1 } },
|
|
621
|
+
{ id: 'close-border-radius', label: 'Border Radius', type: 'slider', path: 'launcher.closeButtonBorderRadius', defaultValue: '50%', slider: { min: 0, max: 100, step: 1, isRadiusFull: true } },
|
|
622
|
+
{ id: 'close-icon-name', label: 'Icon Name', type: 'text', path: 'launcher.closeButtonIconName', defaultValue: 'x' },
|
|
623
|
+
{ id: 'close-icon-text', label: 'Icon Text', type: 'text', path: 'launcher.closeButtonIconText', defaultValue: '×' },
|
|
624
|
+
{ id: 'close-show-tooltip', label: 'Show Tooltip', type: 'toggle', path: 'launcher.closeButtonShowTooltip', defaultValue: true },
|
|
625
|
+
{ id: 'close-tooltip-text', label: 'Tooltip Text', type: 'text', path: 'launcher.closeButtonTooltipText', defaultValue: 'Close chat' },
|
|
626
|
+
],
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
const clearChatSectionDef: SectionDef = {
|
|
630
|
+
id: 'clear-chat', title: 'Clear Chat Button', collapsed: true,
|
|
631
|
+
fields: [
|
|
632
|
+
{ id: 'clear-enabled', label: 'Enabled', type: 'toggle', path: 'launcher.clearChat.enabled', defaultValue: true },
|
|
633
|
+
{ id: 'clear-placement', label: 'Placement', type: 'select', path: 'launcher.clearChat.placement', defaultValue: 'inline', options: [{ value: 'inline', label: 'Inline' }, { value: 'top-right', label: 'Top Right' }] },
|
|
634
|
+
{ id: 'clear-icon-name', label: 'Icon Name', type: 'text', path: 'launcher.clearChat.iconName', defaultValue: 'refresh-cw' },
|
|
635
|
+
{ id: 'clear-size', label: 'Size', type: 'slider', path: 'launcher.clearChat.size', defaultValue: '32px', slider: { min: 16, max: 64, step: 1 } },
|
|
636
|
+
{ id: 'clear-show-tooltip', label: 'Show Tooltip', type: 'toggle', path: 'launcher.clearChat.showTooltip', defaultValue: true },
|
|
637
|
+
{ id: 'clear-tooltip-text', label: 'Tooltip Text', type: 'text', path: 'launcher.clearChat.tooltipText', defaultValue: 'Clear chat' },
|
|
638
|
+
],
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
const statusIndicatorSectionDef: SectionDef = {
|
|
642
|
+
id: 'status-indicator', title: 'Status Indicator', collapsed: true,
|
|
643
|
+
fields: [
|
|
644
|
+
{ id: 'status-visible', label: 'Visible', type: 'toggle', path: 'statusIndicator.visible', defaultValue: true },
|
|
645
|
+
{ id: 'status-align', label: 'Alignment', type: 'select', path: 'statusIndicator.align', defaultValue: 'right', options: [{ value: 'left', label: 'Left' }, { value: 'center', label: 'Center' }, { value: 'right', label: 'Right' }] },
|
|
646
|
+
{ id: 'status-idle-text', label: 'Idle Text', type: 'text', path: 'statusIndicator.idleText', defaultValue: 'Online' },
|
|
647
|
+
{ id: 'status-connecting-text', label: 'Connecting Text', type: 'text', path: 'statusIndicator.connectingText', defaultValue: 'Connecting…' },
|
|
648
|
+
{ id: 'status-connected-text', label: 'Connected Text', type: 'text', path: 'statusIndicator.connectedText', defaultValue: 'Streaming…' },
|
|
649
|
+
{ id: 'status-error-text', label: 'Error Text', type: 'text', path: 'statusIndicator.errorText', defaultValue: 'Offline' },
|
|
650
|
+
],
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
const featuresSectionDef: SectionDef = {
|
|
654
|
+
id: 'features', title: 'Features', collapsed: true,
|
|
655
|
+
fields: [
|
|
656
|
+
{ id: 'feat-voice', label: 'Voice Recognition', description: 'Enable voice input', type: 'toggle', path: 'voiceRecognition.enabled', defaultValue: false },
|
|
657
|
+
{ id: 'feat-auto-focus', label: 'Auto Focus Input', description: 'Focus input after panel opens', type: 'toggle', path: 'autoFocusInput', defaultValue: false },
|
|
658
|
+
],
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
const attachmentsSectionDef: SectionDef = {
|
|
662
|
+
id: 'attachments-config', title: 'Attachments', collapsed: true,
|
|
663
|
+
fields: [
|
|
664
|
+
{ id: 'attach-enabled', label: 'Enabled', type: 'toggle', path: 'attachments.enabled', defaultValue: false },
|
|
665
|
+
{ id: 'attach-max-files', label: 'Max Files', type: 'select', path: 'attachments.maxFiles', defaultValue: 4, options: [{ value: '1', label: '1' }, { value: '2', label: '2' }, { value: '4', label: '4' }, { value: '6', label: '6' }, { value: '8', label: '8' }, { value: '10', label: '10' }], formatValue: (v: unknown) => String(v ?? 4), parseValue: (v: unknown) => Number(v) },
|
|
666
|
+
{ id: 'attach-max-size', label: 'Max File Size (MB)', type: 'select', path: 'attachments.maxFileSize', defaultValue: 10 * MB, options: [{ value: '1', label: '1 MB' }, { value: '5', label: '5 MB' }, { value: '10', label: '10 MB' }, { value: '25', label: '25 MB' }, { value: '50', label: '50 MB' }], formatValue: formatAttachmentMaxFileSize, parseValue: parseAttachmentMaxFileSize },
|
|
667
|
+
{ id: 'attach-types', label: 'Allowed File Types', type: 'select', path: 'attachments.allowedTypes', defaultValue: ATTACHMENT_TYPE_PRESETS.images, options: [{ value: 'images', label: 'Images only' }, { value: 'images-pdf', label: 'Images + PDF' }, { value: 'images-text-pdf', label: 'Images + text + PDF' }, { value: 'all', label: 'All supported types' }], formatValue: formatAttachmentAllowedTypes, parseValue: parseAttachmentAllowedTypes },
|
|
668
|
+
],
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const artifactsSectionDef: SectionDef = {
|
|
672
|
+
id: 'artifacts-config', title: 'Artifacts', collapsed: true,
|
|
673
|
+
fields: [
|
|
674
|
+
{ id: 'art-enabled', label: 'Enabled', description: 'Show artifact sidebar for documents and components', type: 'toggle', path: 'features.artifacts.enabled', defaultValue: false },
|
|
675
|
+
{ id: 'art-appearance', label: 'Pane Appearance', type: 'select', path: 'features.artifacts.layout.paneAppearance', defaultValue: 'panel', options: [{ value: 'panel', label: 'Panel (bordered)' }, { value: 'seamless', label: 'Seamless' }] },
|
|
676
|
+
],
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
const artifactCustomizationSectionDef: SectionDef = {
|
|
680
|
+
id: 'artifacts-customization', title: 'Artifact Customization', collapsed: true,
|
|
681
|
+
fields: [
|
|
682
|
+
{ id: 'art-toolbar', label: 'Toolbar Preset', type: 'select', path: 'features.artifacts.layout.toolbarPreset', defaultValue: 'default', options: [{ value: 'default', label: 'Default' }, { value: 'document', label: 'Document' }] },
|
|
683
|
+
{ id: 'art-pane-width', label: 'Pane Width', description: 'CSS width (e.g. 40%, 28rem)', type: 'text', path: 'features.artifacts.layout.paneWidth', defaultValue: '40%' },
|
|
684
|
+
{ id: 'art-pane-max-width', label: 'Pane Max Width', type: 'text', path: 'features.artifacts.layout.paneMaxWidth', defaultValue: '28rem' },
|
|
685
|
+
{ id: 'art-split-gap', label: 'Split Gap', type: 'text', path: 'features.artifacts.layout.splitGap', defaultValue: '0.5rem' },
|
|
686
|
+
{ id: 'art-pane-bg', label: 'Pane Background', type: 'color', path: 'features.artifacts.layout.paneBackground', defaultValue: '' },
|
|
687
|
+
{ id: 'art-unified', label: 'Unified Split Chrome', description: 'Wrap chat and artifact in a single container', type: 'toggle', path: 'features.artifacts.layout.unifiedSplitChrome', defaultValue: false },
|
|
688
|
+
{ id: 'art-resizable', label: 'Resizable', description: 'Allow dragging the pane divider', type: 'toggle', path: 'features.artifacts.layout.resizable', defaultValue: false },
|
|
689
|
+
{ id: 'art-expand-panel', label: 'Expand Panel When Open', description: 'Widen the launcher panel to fit artifacts', type: 'toggle', path: 'features.artifacts.layout.expandLauncherPanelWhenOpen', defaultValue: true },
|
|
690
|
+
],
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
const apiIntegrationSectionDef: SectionDef = {
|
|
694
|
+
id: 'api-integration', title: 'API & Integration', description: 'Runtime and integration options.', collapsed: true,
|
|
695
|
+
fields: [
|
|
696
|
+
{ id: 'dev-api-url', label: 'API URL', type: 'text', path: 'apiUrl', defaultValue: '' },
|
|
697
|
+
{ id: 'dev-flow', label: 'Flow ID', type: 'text', path: 'flowId', defaultValue: '' },
|
|
698
|
+
{ id: 'dev-parser', label: 'Stream Parser', type: 'select', path: 'parserType', defaultValue: 'plain', options: [{ value: 'plain', label: 'Plain Text' }, { value: 'json', label: 'JSON' }, { value: 'regex-json', label: 'Regex JSON' }, { value: 'xml', label: 'XML' }] },
|
|
699
|
+
],
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
const debugSectionDef: SectionDef = {
|
|
703
|
+
id: 'debug-inspection', title: 'Debug & Inspection', collapsed: true,
|
|
704
|
+
fields: [
|
|
705
|
+
{ id: 'dev-reasoning', label: 'Show Reasoning', description: 'Display AI reasoning steps', type: 'toggle', path: 'features.showReasoning', defaultValue: false },
|
|
706
|
+
{ id: 'dev-tool-calls', label: 'Show Tool Calls', description: 'Display tool call details', type: 'toggle', path: 'features.showToolCalls', defaultValue: false },
|
|
707
|
+
{ id: 'dev-debug', label: 'Debug Mode', description: 'Show debug information', type: 'toggle', path: 'debug', defaultValue: false },
|
|
708
|
+
],
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
const markdownSectionDef: SectionDef = {
|
|
712
|
+
id: 'markdown', title: 'Markdown Options', collapsed: true,
|
|
713
|
+
fields: [
|
|
714
|
+
{ id: 'md-gfm', label: 'GitHub Flavored Markdown', type: 'toggle', path: 'markdown.options.gfm', defaultValue: true },
|
|
715
|
+
{ id: 'md-breaks', label: 'Line Breaks', type: 'toggle', path: 'markdown.options.breaks', defaultValue: true },
|
|
716
|
+
{ id: 'md-header-ids', label: 'Header IDs', type: 'toggle', path: 'markdown.options.headerIds', defaultValue: false },
|
|
717
|
+
{ id: 'md-pedantic', label: 'Pedantic Mode', type: 'toggle', path: 'markdown.options.pedantic', defaultValue: false },
|
|
718
|
+
{ id: 'md-silent', label: 'Silent', type: 'toggle', path: 'markdown.options.silent', defaultValue: false },
|
|
719
|
+
{ id: 'md-disable-styles', label: 'Disable Default Styles', type: 'toggle', path: 'markdown.disableDefaultStyles', defaultValue: false },
|
|
720
|
+
],
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
export const CONFIGURE_SUB_GROUPS: SubGroupDef[] = [
|
|
724
|
+
{ label: 'Content', sections: [copySectionDef, suggestionsSectionDef] },
|
|
725
|
+
{ label: 'Layout', sections: [generalLayoutSectionDef, headerLayoutSectionDef, messagesLayoutSectionDef, messageActionsSectionDef] },
|
|
726
|
+
{ label: 'Widget', sections: [launcherBasicsSectionDef, launcherAdvancedSectionDef, sendButtonSectionDef, closeButtonSectionDef, clearChatSectionDef, statusIndicatorSectionDef] },
|
|
727
|
+
{ label: 'Features', sections: [featuresSectionDef, attachmentsSectionDef, artifactsSectionDef, artifactCustomizationSectionDef] },
|
|
728
|
+
{ label: 'Developer', collapsedByDefault: true, sections: [apiIntegrationSectionDef, debugSectionDef, markdownSectionDef] },
|
|
729
|
+
];
|
|
730
|
+
|
|
731
|
+
export const CONFIGURE_SECTIONS: SectionDef[] = CONFIGURE_SUB_GROUPS.flatMap(g => g.sections);
|
|
732
|
+
|
|
733
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
734
|
+
// STYLE TAB V2 — outcome-oriented editor structure
|
|
735
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
736
|
+
|
|
737
|
+
/** Section 1: Theme — color mode selection */
|
|
738
|
+
export const THEME_SECTION: SectionDef = {
|
|
739
|
+
id: 'theme-mode-v2',
|
|
740
|
+
title: 'Theme',
|
|
741
|
+
description: 'Choose how the interface adapts across light and dark mode.',
|
|
742
|
+
collapsed: false,
|
|
743
|
+
fields: [
|
|
744
|
+
{
|
|
745
|
+
id: 'color-mode',
|
|
746
|
+
label: 'Color Mode',
|
|
747
|
+
type: 'select',
|
|
748
|
+
path: 'colorScheme',
|
|
749
|
+
defaultValue: 'auto',
|
|
750
|
+
options: [
|
|
751
|
+
{ value: 'auto', label: 'Auto' },
|
|
752
|
+
{ value: 'light', label: 'Light' },
|
|
753
|
+
{ value: 'dark', label: 'Dark' },
|
|
754
|
+
],
|
|
755
|
+
},
|
|
756
|
+
],
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
/** Section 2: Brand Palette — primary colors + collapsed status colors */
|
|
760
|
+
export const BRAND_PALETTE_SECTION: SectionDef = {
|
|
761
|
+
id: 'brand-palette-v2',
|
|
762
|
+
title: 'Brand Palette',
|
|
763
|
+
description: 'Set your brand, accent, and neutral colors. These are used to generate the interface theme.',
|
|
764
|
+
collapsed: false,
|
|
765
|
+
fields: [
|
|
766
|
+
{ id: 'bp-primary', label: 'Primary', description: 'Main brand color', type: 'color', path: 'theme.palette.colors.primary.500', defaultValue: '#171717' },
|
|
767
|
+
{ id: 'bp-secondary', label: 'Secondary', description: 'Supporting brand color', type: 'color', path: 'theme.palette.colors.secondary.500', defaultValue: '#8b5cf6' },
|
|
768
|
+
{ id: 'bp-accent', label: 'Accent', description: 'Highlight and decorative color', type: 'color', path: 'theme.palette.colors.accent.500', defaultValue: '#06b6d4' },
|
|
769
|
+
{ id: 'bp-neutral', label: 'Neutral', description: 'Backgrounds, text, and borders', type: 'color', path: 'theme.palette.colors.gray.500', defaultValue: '#6b7280' },
|
|
770
|
+
],
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
/** Section 2b: Status palette — collapsed under Brand Palette */
|
|
774
|
+
export const STATUS_PALETTE_SECTION: SectionDef = {
|
|
775
|
+
id: 'status-palette',
|
|
776
|
+
title: 'Status Palette',
|
|
777
|
+
description: 'Colors for system feedback states.',
|
|
778
|
+
collapsed: true,
|
|
779
|
+
fields: [
|
|
780
|
+
{ id: 'sp-success', label: 'Success', type: 'color', path: 'theme.palette.colors.success.500', defaultValue: '#22c55e' },
|
|
781
|
+
{ id: 'sp-warning', label: 'Warning', type: 'color', path: 'theme.palette.colors.warning.500', defaultValue: '#eab308' },
|
|
782
|
+
{ id: 'sp-error', label: 'Error', type: 'color', path: 'theme.palette.colors.error.500', defaultValue: '#ef4444' },
|
|
783
|
+
{ id: 'sp-notice', label: 'Notice', description: 'Info and notice states', type: 'color', path: 'theme.semantic.colors.feedback.info', defaultValue: 'palette.colors.primary.500' },
|
|
784
|
+
],
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
/** Section 3: Interface Roles — the main theming surface */
|
|
788
|
+
export const INTERFACE_ROLES_SECTION: SectionDef = {
|
|
789
|
+
id: 'interface-roles',
|
|
790
|
+
title: 'Interface Roles',
|
|
791
|
+
description: 'Control where brand and neutral colors appear across the interface.',
|
|
792
|
+
collapsed: false,
|
|
793
|
+
fields: [
|
|
794
|
+
{
|
|
795
|
+
id: 'role-surfaces',
|
|
796
|
+
label: 'Background Surfaces',
|
|
797
|
+
type: 'role-assignment',
|
|
798
|
+
path: 'theme.semantic.colors.background', // primary target for detection
|
|
799
|
+
roleAssignment: ROLE_SURFACES,
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
id: 'role-header',
|
|
803
|
+
label: 'Header',
|
|
804
|
+
type: 'role-assignment',
|
|
805
|
+
path: 'theme.components.header.background',
|
|
806
|
+
roleAssignment: ROLE_HEADER,
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
id: 'role-user-messages',
|
|
810
|
+
label: 'User Messages',
|
|
811
|
+
type: 'role-assignment',
|
|
812
|
+
path: 'theme.components.message.user.background',
|
|
813
|
+
roleAssignment: ROLE_USER_MESSAGES,
|
|
814
|
+
},
|
|
815
|
+
{
|
|
816
|
+
id: 'role-assistant-messages',
|
|
817
|
+
label: 'Assistant Messages',
|
|
818
|
+
type: 'role-assignment',
|
|
819
|
+
path: 'theme.components.message.assistant.background',
|
|
820
|
+
roleAssignment: ROLE_ASSISTANT_MESSAGES,
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
id: 'role-primary-actions',
|
|
824
|
+
label: 'Primary Actions',
|
|
825
|
+
type: 'role-assignment',
|
|
826
|
+
path: 'theme.components.button.primary.background',
|
|
827
|
+
roleAssignment: ROLE_PRIMARY_ACTIONS,
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
id: 'role-input',
|
|
831
|
+
label: 'Input Field',
|
|
832
|
+
type: 'role-assignment',
|
|
833
|
+
path: 'theme.components.input.background',
|
|
834
|
+
roleAssignment: ROLE_INPUT,
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
id: 'role-links-focus',
|
|
838
|
+
label: 'Links & Focus',
|
|
839
|
+
type: 'role-assignment',
|
|
840
|
+
path: 'theme.semantic.colors.accent',
|
|
841
|
+
roleAssignment: ROLE_LINKS_FOCUS,
|
|
842
|
+
},
|
|
843
|
+
{
|
|
844
|
+
id: 'role-borders',
|
|
845
|
+
label: 'Borders & Dividers',
|
|
846
|
+
type: 'role-assignment',
|
|
847
|
+
path: 'theme.semantic.colors.border',
|
|
848
|
+
roleAssignment: ROLE_BORDERS,
|
|
849
|
+
},
|
|
850
|
+
],
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
/** Section 4: Status Colors — feedback semantic tokens */
|
|
854
|
+
export const STATUS_COLORS_SECTION: SectionDef = {
|
|
855
|
+
id: 'status-colors',
|
|
856
|
+
title: 'Status Colors',
|
|
857
|
+
description: 'Used for system states like success, warning, notice, and error.',
|
|
858
|
+
collapsed: true,
|
|
859
|
+
fields: [
|
|
860
|
+
{ id: 'sc-notice', label: 'Notice', type: 'token-ref', path: 'theme.semantic.colors.feedback.info', defaultValue: 'palette.colors.primary.500', tokenRef: { tokenType: 'color' } },
|
|
861
|
+
{ id: 'sc-success', label: 'Success', type: 'token-ref', path: 'theme.semantic.colors.feedback.success', defaultValue: 'palette.colors.success.500', tokenRef: { tokenType: 'color' } },
|
|
862
|
+
{ id: 'sc-warning', label: 'Warning', type: 'token-ref', path: 'theme.semantic.colors.feedback.warning', defaultValue: 'palette.colors.warning.500', tokenRef: { tokenType: 'color' } },
|
|
863
|
+
{ id: 'sc-error', label: 'Error', type: 'token-ref', path: 'theme.semantic.colors.feedback.error', defaultValue: 'palette.colors.error.500', tokenRef: { tokenType: 'color' } },
|
|
864
|
+
],
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
/** Section 5: Advanced Tokens — entry point for drill-downs (no fields) */
|
|
868
|
+
export const ADVANCED_TOKENS_SECTION: SectionDef = {
|
|
869
|
+
id: 'advanced-tokens',
|
|
870
|
+
title: 'Advanced Tokens',
|
|
871
|
+
description: 'Override individual semantic and component values when you need precise control.',
|
|
872
|
+
collapsed: true,
|
|
873
|
+
fields: [],
|
|
874
|
+
};
|
|
875
|
+
|
|
876
|
+
/** V2 Style tab sections — outcome-oriented editor */
|
|
877
|
+
export const STYLE_SECTIONS_V2: SectionDef[] = [
|
|
878
|
+
THEME_SECTION,
|
|
879
|
+
BRAND_PALETTE_SECTION,
|
|
880
|
+
STATUS_PALETTE_SECTION,
|
|
881
|
+
INTERFACE_ROLES_SECTION,
|
|
882
|
+
STATUS_COLORS_SECTION,
|
|
883
|
+
ADVANCED_TOKENS_SECTION,
|
|
884
|
+
];
|
|
885
|
+
|
|
886
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
887
|
+
// ALL TABS
|
|
888
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
889
|
+
|
|
890
|
+
export const ALL_TABS: TabDef[] = [
|
|
891
|
+
{ id: 'style', label: 'Style', sections: STYLE_SECTIONS },
|
|
892
|
+
{ id: 'design-system', label: 'Design System', sections: COMPONENTS_SECTIONS },
|
|
893
|
+
{ id: 'configure', label: 'Configure', sections: CONFIGURE_SECTIONS },
|
|
894
|
+
];
|
|
895
|
+
|
|
896
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
897
|
+
// HELPERS — light/dark scoping for dual-mode editing
|
|
898
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
899
|
+
|
|
900
|
+
type ThemeScope = 'theme' | 'darkTheme';
|
|
901
|
+
type ThemeVariant = 'light' | 'dark';
|
|
902
|
+
|
|
903
|
+
function scopePath(path: string, scope: ThemeScope): string {
|
|
904
|
+
return path.startsWith('theme.') ? path.replace(/^theme\./, `${scope}.`) : path;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
function scopeField(field: FieldDef, scope: ThemeScope, variant: ThemeVariant): FieldDef {
|
|
908
|
+
return {
|
|
909
|
+
...field,
|
|
910
|
+
id: `${variant}-${field.id}`,
|
|
911
|
+
path: scopePath(field.path, scope),
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/** Look up a section by ID from an array of sections */
|
|
916
|
+
export function findSection(sections: SectionDef[], id: string): SectionDef {
|
|
917
|
+
const found = sections.find(s => s.id === id);
|
|
918
|
+
if (!found) throw new Error(`Section "${id}" not found in definitions`);
|
|
919
|
+
return found;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/** Create a light/dark scoped copy of a section */
|
|
923
|
+
export function scopeSection(
|
|
924
|
+
section: SectionDef,
|
|
925
|
+
scope: ThemeScope,
|
|
926
|
+
variant: ThemeVariant,
|
|
927
|
+
collapsed = section.collapsed
|
|
928
|
+
): SectionDef {
|
|
929
|
+
const themeLabel = variant === 'light' ? 'Light' : 'Dark';
|
|
930
|
+
const descriptionPrefix =
|
|
931
|
+
variant === 'light'
|
|
932
|
+
? 'Applies when the widget is in light mode.'
|
|
933
|
+
: 'Applies when the widget is in dark mode.';
|
|
934
|
+
|
|
935
|
+
return {
|
|
936
|
+
...section,
|
|
937
|
+
id: `${variant}-${section.id}`,
|
|
938
|
+
title: `${themeLabel} ${section.title}`,
|
|
939
|
+
description: section.description
|
|
940
|
+
? `${descriptionPrefix} ${section.description}`
|
|
941
|
+
: descriptionPrefix,
|
|
942
|
+
collapsed,
|
|
943
|
+
fields: section.fields.map(field => scopeField(field, scope, variant)),
|
|
944
|
+
presets: section.presets?.map(preset => ({
|
|
945
|
+
...preset,
|
|
946
|
+
id: `${variant}-${preset.id}`,
|
|
947
|
+
values: Object.fromEntries(
|
|
948
|
+
Object.entries(preset.values).map(([path, value]) => [scopePath(path as string, scope), value])
|
|
949
|
+
),
|
|
950
|
+
})),
|
|
951
|
+
};
|
|
952
|
+
}
|