@runtypelabs/persona 3.5.2 → 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,144 @@
|
|
|
1
|
+
/** Theme editor presets — unified collection of built-in presets */
|
|
2
|
+
|
|
3
|
+
import type { ThemeEditorPreset } from './types';
|
|
4
|
+
|
|
5
|
+
export const BUILT_IN_PRESETS: ThemeEditorPreset[] = [
|
|
6
|
+
{
|
|
7
|
+
id: 'default-light',
|
|
8
|
+
name: 'Default Light',
|
|
9
|
+
description: 'Clean monochrome light theme',
|
|
10
|
+
theme: {
|
|
11
|
+
components: {
|
|
12
|
+
artifact: {
|
|
13
|
+
pane: {
|
|
14
|
+
background: 'semantic.colors.container',
|
|
15
|
+
toolbarBackground: 'semantic.colors.container',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
preview: { primary: '#171717', surface: '#ffffff', accent: '#0f0f0f' },
|
|
21
|
+
tags: ['light'],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'default-dark',
|
|
25
|
+
name: 'Default Dark',
|
|
26
|
+
description: 'Monochrome dark theme',
|
|
27
|
+
theme: {
|
|
28
|
+
palette: {
|
|
29
|
+
colors: {
|
|
30
|
+
primary: {
|
|
31
|
+
50: '#ffffff', 100: '#f5f5f5', 200: '#d4d4d4', 300: '#a3a3a3',
|
|
32
|
+
400: '#737373', 500: '#171717', 600: '#0f0f0f', 700: '#0a0a0a',
|
|
33
|
+
800: '#050505', 900: '#030303', 950: '#000000',
|
|
34
|
+
},
|
|
35
|
+
gray: {
|
|
36
|
+
50: '#f9fafb', 100: '#f3f4f6', 200: '#e5e7eb', 300: '#d1d5db',
|
|
37
|
+
400: '#9ca3af', 500: '#6b7280', 600: '#4b5563', 700: '#374151',
|
|
38
|
+
800: '#1f2937', 900: '#111827', 950: '#030712',
|
|
39
|
+
},
|
|
40
|
+
secondary: {
|
|
41
|
+
50: '#f5f3ff', 100: '#ede9fe', 200: '#ddd6fe', 300: '#c4b5fd',
|
|
42
|
+
400: '#a78bfa', 500: '#8b5cf6', 600: '#7c3aed', 700: '#6d28d9',
|
|
43
|
+
800: '#5b21b6', 900: '#4c1d95', 950: '#2e1065',
|
|
44
|
+
},
|
|
45
|
+
accent: {
|
|
46
|
+
50: '#ecfeff', 100: '#cffafe', 200: '#a5f3fc', 300: '#67e8f9',
|
|
47
|
+
400: '#22d3ee', 500: '#06b6d4', 600: '#0891b2', 700: '#0e7490',
|
|
48
|
+
800: '#155e75', 900: '#164e63', 950: '#083344',
|
|
49
|
+
},
|
|
50
|
+
success: {
|
|
51
|
+
50: '#f0fdf4', 100: '#dcfce7', 200: '#bbf7d0', 300: '#86efac',
|
|
52
|
+
400: '#4ade80', 500: '#22c55e', 600: '#16a34a', 700: '#15803d',
|
|
53
|
+
800: '#166534', 900: '#14532d',
|
|
54
|
+
},
|
|
55
|
+
warning: {
|
|
56
|
+
50: '#fefce8', 100: '#fef9c3', 200: '#fef08a', 300: '#fde047',
|
|
57
|
+
400: '#facc15', 500: '#eab308', 600: '#ca8a04', 700: '#a16207',
|
|
58
|
+
800: '#854d0e', 900: '#713f12',
|
|
59
|
+
},
|
|
60
|
+
error: {
|
|
61
|
+
50: '#fef2f2', 100: '#fee2e2', 200: '#fecaca', 300: '#fca5a5',
|
|
62
|
+
400: '#f87171', 500: '#ef4444', 600: '#dc2626', 700: '#b91c1c',
|
|
63
|
+
800: '#991b1b', 900: '#7f1d1d',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
} as any,
|
|
67
|
+
semantic: {
|
|
68
|
+
colors: {
|
|
69
|
+
primary: 'palette.colors.primary.400',
|
|
70
|
+
secondary: 'palette.colors.gray.400',
|
|
71
|
+
accent: 'palette.colors.primary.500',
|
|
72
|
+
surface: 'palette.colors.gray.800',
|
|
73
|
+
background: 'palette.colors.gray.900',
|
|
74
|
+
container: 'palette.colors.gray.800',
|
|
75
|
+
text: 'palette.colors.gray.100',
|
|
76
|
+
textMuted: 'palette.colors.gray.400',
|
|
77
|
+
textInverse: 'palette.colors.gray.900',
|
|
78
|
+
border: 'palette.colors.gray.700',
|
|
79
|
+
divider: 'palette.colors.gray.700',
|
|
80
|
+
interactive: {
|
|
81
|
+
default: 'palette.colors.primary.400',
|
|
82
|
+
hover: 'palette.colors.primary.300',
|
|
83
|
+
focus: 'palette.colors.primary.500',
|
|
84
|
+
active: 'palette.colors.primary.600',
|
|
85
|
+
disabled: 'palette.colors.gray.600',
|
|
86
|
+
},
|
|
87
|
+
feedback: {
|
|
88
|
+
success: 'palette.colors.success.400',
|
|
89
|
+
warning: 'palette.colors.warning.400',
|
|
90
|
+
error: 'palette.colors.error.400',
|
|
91
|
+
info: 'palette.colors.primary.400',
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
} as any,
|
|
95
|
+
},
|
|
96
|
+
preview: { primary: '#171717', surface: '#1f2937', accent: '#0f0f0f' },
|
|
97
|
+
tags: ['dark'],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 'high-contrast',
|
|
101
|
+
name: 'High Contrast',
|
|
102
|
+
description: 'Maximum contrast for accessibility',
|
|
103
|
+
theme: {
|
|
104
|
+
semantic: {
|
|
105
|
+
colors: {
|
|
106
|
+
primary: 'palette.colors.primary.700',
|
|
107
|
+
secondary: 'palette.colors.gray.700',
|
|
108
|
+
accent: 'palette.colors.primary.800',
|
|
109
|
+
surface: 'palette.colors.gray.50',
|
|
110
|
+
background: 'palette.colors.gray.50',
|
|
111
|
+
container: 'palette.colors.gray.200',
|
|
112
|
+
text: 'palette.colors.gray.950',
|
|
113
|
+
textMuted: 'palette.colors.gray.700',
|
|
114
|
+
textInverse: 'palette.colors.gray.50',
|
|
115
|
+
border: 'palette.colors.gray.400',
|
|
116
|
+
divider: 'palette.colors.gray.400',
|
|
117
|
+
interactive: {
|
|
118
|
+
default: 'palette.colors.primary.700',
|
|
119
|
+
hover: 'palette.colors.primary.800',
|
|
120
|
+
focus: 'palette.colors.primary.900',
|
|
121
|
+
active: 'palette.colors.primary.950',
|
|
122
|
+
disabled: 'palette.colors.gray.400',
|
|
123
|
+
},
|
|
124
|
+
feedback: {
|
|
125
|
+
success: 'palette.colors.success.700',
|
|
126
|
+
warning: 'palette.colors.warning.700',
|
|
127
|
+
error: 'palette.colors.error.700',
|
|
128
|
+
info: 'palette.colors.primary.700',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
} as any,
|
|
132
|
+
},
|
|
133
|
+
preview: { primary: '#0a0a0a', surface: '#f9fafb', accent: '#050505' },
|
|
134
|
+
tags: ['light', 'high-contrast', 'accessibility'],
|
|
135
|
+
},
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
/** All built-in presets */
|
|
139
|
+
export const THEME_EDITOR_PRESETS: ThemeEditorPreset[] = [...BUILT_IN_PRESETS];
|
|
140
|
+
|
|
141
|
+
/** Look up a preset by ID */
|
|
142
|
+
export function getThemeEditorPreset(id: string): ThemeEditorPreset | undefined {
|
|
143
|
+
return THEME_EDITOR_PRESETS.find(p => p.id === id);
|
|
144
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared preview building blocks for theme editor preview renderers.
|
|
3
|
+
* Used by both `createThemePreview()` (simple API) and the configurator's
|
|
4
|
+
* advanced preview system. Separate file for code-splitting.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { AgentWidgetConfig } from '../types';
|
|
8
|
+
import type { AgentWidgetMessage } from '../types';
|
|
9
|
+
import { createTheme } from '../utils/theme';
|
|
10
|
+
import { DEFAULT_WIDGET_CONFIG } from '../defaults';
|
|
11
|
+
|
|
12
|
+
// ─── Constants ──────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
export const DEVICE_DIMENSIONS: Record<string, { w: number; h: number }> = {
|
|
15
|
+
desktop: { w: 1280, h: 800 },
|
|
16
|
+
mobile: { w: 390, h: 844 },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const ZOOM_MIN = 0.15;
|
|
20
|
+
export const ZOOM_MAX = 1.5;
|
|
21
|
+
|
|
22
|
+
export const SHELL_STYLE_ID = 'persona-preview-shell-theme';
|
|
23
|
+
|
|
24
|
+
export const PREVIEW_STORAGE_ADAPTER = {
|
|
25
|
+
load: () => null,
|
|
26
|
+
save: () => {},
|
|
27
|
+
clear: () => {},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const HOME_SUGGESTION_CHIPS = [
|
|
31
|
+
'How do I get started?',
|
|
32
|
+
'Pricing & plans',
|
|
33
|
+
'Talk to support',
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
// ─── HTML Escaping ──────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
export function escapeHtml(str: string): string {
|
|
39
|
+
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ─── Shell Theme ────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
export type PreviewShellPalette = {
|
|
45
|
+
pageBg: string;
|
|
46
|
+
chromeBg: string;
|
|
47
|
+
chromeBorder: string;
|
|
48
|
+
dot: string;
|
|
49
|
+
skeleton: string;
|
|
50
|
+
cardBg: string;
|
|
51
|
+
cardBorder: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export function getShellPalette(shellMode: 'light' | 'dark'): PreviewShellPalette {
|
|
55
|
+
return shellMode === 'dark'
|
|
56
|
+
? {
|
|
57
|
+
pageBg: 'linear-gradient(180deg, #0f172a 0%, #020617 100%)',
|
|
58
|
+
chromeBg: '#111827', chromeBorder: '#1f2937', dot: '#475569',
|
|
59
|
+
skeleton: '#334155', cardBg: '#1e293b', cardBorder: 'rgba(148, 163, 184, 0.16)',
|
|
60
|
+
}
|
|
61
|
+
: {
|
|
62
|
+
pageBg: 'linear-gradient(180deg, #ffffff 0%, #f8fafc 100%)',
|
|
63
|
+
chromeBg: '#ffffff', chromeBorder: '#e5e7eb', dot: '#cbd5e1',
|
|
64
|
+
skeleton: '#e2e8f0', cardBg: '#e2e8f0', cardBorder: 'rgba(148, 163, 184, 0.18)',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function buildShellCss(shellMode: 'light' | 'dark'): string {
|
|
69
|
+
const t = getShellPalette(shellMode);
|
|
70
|
+
return `* { box-sizing: border-box; }
|
|
71
|
+
html, body { margin: 0; padding: 0; height: 100%; overflow: hidden; }
|
|
72
|
+
html { color-scheme: ${shellMode}; }
|
|
73
|
+
body { font-family: system-ui, sans-serif; background: ${t.pageBg}; }
|
|
74
|
+
.preview-iframe-mock { min-height: 100%; }
|
|
75
|
+
.preview-iframe-chrome { height: 44px; border-bottom: 1px solid ${t.chromeBorder}; background: ${t.chromeBg}; display: flex; align-items: center; gap: 8px; padding: 0 14px; }
|
|
76
|
+
.preview-iframe-dot { width: 10px; height: 10px; border-radius: 50%; background: ${t.dot}; }
|
|
77
|
+
.preview-iframe-copy { padding: 32px; }
|
|
78
|
+
.preview-iframe-line { border-radius: 999px; background: ${t.skeleton}; margin-bottom: 12px; }
|
|
79
|
+
.preview-iframe-line.hero { width: 48%; height: 16px; }
|
|
80
|
+
.preview-iframe-line.body { width: 72%; height: 10px; }
|
|
81
|
+
.preview-iframe-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 24px 0; }
|
|
82
|
+
.preview-iframe-card { height: 84px; border-radius: 14px; background: ${t.cardBg}; box-shadow: inset 0 0 0 1px ${t.cardBorder}; }
|
|
83
|
+
.preview-workspace-shell { height: 100%; min-height: 100%; display: flex; flex-direction: column; }
|
|
84
|
+
.preview-workspace-topbar { height: 52px; flex-shrink: 0; border-bottom: 1px solid ${t.chromeBorder}; background: ${t.chromeBg}; display: flex; align-items: center; justify-content: space-between; padding: 0 18px; }
|
|
85
|
+
.preview-workspace-topbar-left { display: flex; align-items: center; gap: 12px; }
|
|
86
|
+
.preview-workspace-topbar-badge { width: 18px; height: 18px; border-radius: 6px; background: ${t.cardBg}; box-shadow: inset 0 0 0 1px ${t.cardBorder}; }
|
|
87
|
+
.preview-workspace-topbar-line { width: 180px; height: 10px; border-radius: 999px; background: ${t.skeleton}; }
|
|
88
|
+
.preview-workspace-topbar-pill { width: 64px; height: 28px; border-radius: 999px; background: ${t.cardBg}; box-shadow: inset 0 0 0 1px ${t.cardBorder}; }
|
|
89
|
+
.preview-workspace-body { flex: 1; min-height: 0; display: flex; padding: 20px; }
|
|
90
|
+
.preview-workspace-content { position: relative; display: flex; flex-direction: column; flex: 1; width: 100%; height: 100%; min-width: 0; min-height: 0; overflow: hidden; border-radius: 24px; background: rgba(255,255,255,0.72); box-shadow: inset 0 0 0 1px ${t.cardBorder}; }
|
|
91
|
+
.preview-workspace-content-shell { position: relative; z-index: 1; flex: 1 1 auto; min-height: 100%; padding: 24px; }
|
|
92
|
+
.preview-workspace-row { display: flex; gap: 16px; margin-top: 20px; }
|
|
93
|
+
.preview-workspace-card { flex: 1; min-width: 0; height: 168px; border-radius: 18px; background: ${t.cardBg}; box-shadow: inset 0 0 0 1px ${t.cardBorder}; }
|
|
94
|
+
.preview-workspace-card.short { height: 96px; }`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function applyShellTheme(iframe: HTMLIFrameElement, shellMode: 'light' | 'dark'): void {
|
|
98
|
+
const doc = iframe.contentDocument;
|
|
99
|
+
if (!doc?.documentElement) return;
|
|
100
|
+
let style = doc.getElementById(SHELL_STYLE_ID) as HTMLStyleElement | null;
|
|
101
|
+
if (!style) {
|
|
102
|
+
style = doc.createElement('style');
|
|
103
|
+
style.id = SHELL_STYLE_ID;
|
|
104
|
+
doc.head.appendChild(style);
|
|
105
|
+
}
|
|
106
|
+
style.textContent = buildShellCss(shellMode);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ─── Mock HTML Templates ────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
/** Browser chrome mock with skeleton content cards */
|
|
112
|
+
export const MOCK_BROWSER_CONTENT = `
|
|
113
|
+
<div class="preview-iframe-mock" aria-hidden="true">
|
|
114
|
+
<div class="preview-iframe-chrome">
|
|
115
|
+
<span class="preview-iframe-dot"></span>
|
|
116
|
+
<span class="preview-iframe-dot"></span>
|
|
117
|
+
<span class="preview-iframe-dot"></span>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="preview-iframe-copy">
|
|
120
|
+
<div class="preview-iframe-line hero"></div>
|
|
121
|
+
<div class="preview-iframe-line body"></div>
|
|
122
|
+
<div class="preview-iframe-line body"></div>
|
|
123
|
+
<div class="preview-iframe-grid">
|
|
124
|
+
<div class="preview-iframe-card"></div>
|
|
125
|
+
<div class="preview-iframe-card"></div>
|
|
126
|
+
<div class="preview-iframe-card"></div>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="preview-iframe-line body"></div>
|
|
129
|
+
<div class="preview-iframe-line body"></div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>`;
|
|
132
|
+
|
|
133
|
+
/** Docked workspace skeleton (cards + rows inside content area) */
|
|
134
|
+
export const MOCK_WORKSPACE_CONTENT = `
|
|
135
|
+
<div class="preview-workspace-content-shell" aria-hidden="true">
|
|
136
|
+
<div class="preview-iframe-line hero"></div>
|
|
137
|
+
<div class="preview-iframe-line body"></div>
|
|
138
|
+
<div class="preview-workspace-row">
|
|
139
|
+
<div class="preview-workspace-card"></div>
|
|
140
|
+
<div class="preview-workspace-card"></div>
|
|
141
|
+
</div>
|
|
142
|
+
<div class="preview-workspace-row">
|
|
143
|
+
<div class="preview-workspace-card short"></div>
|
|
144
|
+
<div class="preview-workspace-card short"></div>
|
|
145
|
+
<div class="preview-workspace-card short"></div>
|
|
146
|
+
</div>
|
|
147
|
+
</div>`;
|
|
148
|
+
|
|
149
|
+
// ─── Srcdoc Builder ─────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Build a basic iframe srcdoc with mock page chrome and widget mount point.
|
|
153
|
+
* For advanced use cases (background URLs, embed detection), build custom srcdoc
|
|
154
|
+
* using the exported templates and shell CSS utilities.
|
|
155
|
+
*/
|
|
156
|
+
export function buildSrcdoc(
|
|
157
|
+
mountId: string,
|
|
158
|
+
shellMode: 'light' | 'dark',
|
|
159
|
+
docked: boolean,
|
|
160
|
+
widgetCssPath: string
|
|
161
|
+
): string {
|
|
162
|
+
const floatingContent = `
|
|
163
|
+
${MOCK_BROWSER_CONTENT}
|
|
164
|
+
<div style="position:fixed;inset:0;z-index:9999;"><div id="${mountId}" data-mount-id="${mountId}"></div></div>`;
|
|
165
|
+
|
|
166
|
+
const dockedContent = `
|
|
167
|
+
<div class="preview-workspace-shell">
|
|
168
|
+
<div class="preview-workspace-topbar">
|
|
169
|
+
<div class="preview-workspace-topbar-left">
|
|
170
|
+
<span class="preview-workspace-topbar-badge"></span>
|
|
171
|
+
<span class="preview-workspace-topbar-line"></span>
|
|
172
|
+
</div>
|
|
173
|
+
<span class="preview-workspace-topbar-pill"></span>
|
|
174
|
+
</div>
|
|
175
|
+
<div class="preview-workspace-body">
|
|
176
|
+
<div id="preview-content-${mountId}" class="preview-workspace-content" data-mount-id="${mountId}">
|
|
177
|
+
${MOCK_WORKSPACE_CONTENT}
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>`;
|
|
181
|
+
|
|
182
|
+
return `<!DOCTYPE html>
|
|
183
|
+
<html lang="en">
|
|
184
|
+
<head>
|
|
185
|
+
<meta charset="UTF-8">
|
|
186
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
187
|
+
<link rel="stylesheet" href="${escapeHtml(widgetCssPath)}">
|
|
188
|
+
<style id="${SHELL_STYLE_ID}">${buildShellCss(shellMode)}</style>
|
|
189
|
+
</head>
|
|
190
|
+
<body>
|
|
191
|
+
${docked ? dockedContent : floatingContent}
|
|
192
|
+
</body>
|
|
193
|
+
</html>`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ─── Preview Messages ───────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
export type PreviewScene = 'home' | 'conversation' | 'minimized' | 'artifact';
|
|
199
|
+
|
|
200
|
+
export function createPreviewMessages(scene: PreviewScene): AgentWidgetMessage[] {
|
|
201
|
+
if (scene === 'home') {
|
|
202
|
+
return [{ id: 'preview-home-1', role: 'assistant', content: 'Hi there! How can we help today?', createdAt: new Date().toISOString() }];
|
|
203
|
+
}
|
|
204
|
+
if (scene === 'minimized') {
|
|
205
|
+
return [{ id: 'preview-min-1', role: 'assistant', content: 'We are here whenever you are ready.', createdAt: new Date().toISOString() }];
|
|
206
|
+
}
|
|
207
|
+
if (scene === 'artifact') {
|
|
208
|
+
return [
|
|
209
|
+
{ id: 'preview-art-1', role: 'user', content: 'Can you draft a quick overview of the project?', createdAt: new Date(Date.now() - 120000).toISOString() },
|
|
210
|
+
{ id: 'preview-art-2', role: 'assistant', content: 'Here\u2019s a project overview document for you.', createdAt: new Date(Date.now() - 60000).toISOString() },
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
return [
|
|
214
|
+
{ id: 'preview-conv-1', role: 'assistant', content: 'Hello! How can I help you today?', createdAt: new Date(Date.now() - 180000).toISOString() },
|
|
215
|
+
{ id: 'preview-conv-2', role: 'user', content: 'I want to customize the theme editor preview.', createdAt: new Date(Date.now() - 120000).toISOString() },
|
|
216
|
+
{ id: 'preview-conv-3', role: 'assistant', content: 'Absolutely. Check out the [getting started guide](https://example.com) to see what\u2019s possible, then adjust colors and tokens to match your brand.', createdAt: new Date(Date.now() - 60000).toISOString() },
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ─── Scene Config ───────────────────────────────────────────────
|
|
221
|
+
|
|
222
|
+
export function applySceneConfig(base: AgentWidgetConfig, scene: PreviewScene): AgentWidgetConfig {
|
|
223
|
+
const launcher = { ...base.launcher, enabled: true, autoExpand: scene !== 'minimized' };
|
|
224
|
+
const config = {
|
|
225
|
+
...base,
|
|
226
|
+
launcher,
|
|
227
|
+
suggestionChips: scene === 'home' ? (base.suggestionChips?.length ? base.suggestionChips : HOME_SUGGESTION_CHIPS) : base.suggestionChips,
|
|
228
|
+
initialMessages: createPreviewMessages(scene),
|
|
229
|
+
storageAdapter: PREVIEW_STORAGE_ADAPTER,
|
|
230
|
+
} as AgentWidgetConfig;
|
|
231
|
+
|
|
232
|
+
if (scene === 'artifact') {
|
|
233
|
+
config.features = { ...config.features, artifacts: { ...config.features?.artifacts, enabled: true } };
|
|
234
|
+
}
|
|
235
|
+
return config;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ─── Preview Config Builder ─────────────────────────────────────
|
|
239
|
+
|
|
240
|
+
import type { DeepPartial, PersonaTheme } from '../types/theme';
|
|
241
|
+
|
|
242
|
+
export interface PreviewConfigOptions {
|
|
243
|
+
config?: Partial<AgentWidgetConfig>;
|
|
244
|
+
theme?: DeepPartial<PersonaTheme>;
|
|
245
|
+
darkTheme?: DeepPartial<PersonaTheme>;
|
|
246
|
+
scene?: PreviewScene;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function buildPreviewConfig(
|
|
250
|
+
options: PreviewConfigOptions,
|
|
251
|
+
shellModeOverride?: 'light' | 'dark'
|
|
252
|
+
): AgentWidgetConfig {
|
|
253
|
+
const theme = options.theme ? createTheme(options.theme, { validate: false }) : createTheme();
|
|
254
|
+
const scene = options.scene ?? 'conversation';
|
|
255
|
+
|
|
256
|
+
const base = {
|
|
257
|
+
...DEFAULT_WIDGET_CONFIG,
|
|
258
|
+
...options.config,
|
|
259
|
+
theme,
|
|
260
|
+
darkTheme: options.darkTheme,
|
|
261
|
+
colorScheme: shellModeOverride ?? (options.config?.colorScheme as string) ?? 'light',
|
|
262
|
+
} as AgentWidgetConfig;
|
|
263
|
+
|
|
264
|
+
return applySceneConfig(base, scene);
|
|
265
|
+
}
|