@desktalk/miniapp-preference 0.1.0-alpha.1

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.
@@ -0,0 +1,4652 @@
1
+ (() => {
2
+ if (typeof document === 'undefined') return;
3
+ const styleId = "desktalk-style-desktalk-miniapp-preference-19q4gw2";
4
+ if (document.getElementById(styleId)) return;
5
+ const style = document.createElement('style');
6
+ style.id = styleId;
7
+ style.textContent = "/* src/styles/PreferenceApp.module.css */\n.PreferenceApp_root {\n display: flex;\n height: 100%;\n overflow: hidden;\n background: var(--dt-window-body);\n color: var(--dt-text);\n font-family: var(--font-ui, \"Work Sans\", system-ui, -apple-system, sans-serif);\n}\n.PreferenceApp_rootCompact {\n flex-direction: column;\n}\n.PreferenceApp_sidebar {\n width: 180px;\n min-width: 180px;\n display: flex;\n flex-direction: column;\n align-self: stretch;\n overflow-y: auto;\n padding: 8px 0;\n border-right: 1px solid var(--dt-border);\n}\n.PreferenceApp_sidebarHeader {\n padding: 12px 16px 8px;\n color: var(--dt-text-muted);\n font-size: 11px;\n font-weight: 600;\n font-family: var(--font-display, \"Sora\", system-ui, -apple-system, sans-serif);\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n.PreferenceApp_categoryItem {\n display: flex;\n width: 100%;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n border: none;\n background: none;\n color: var(--dt-text);\n cursor: pointer;\n font-family: inherit;\n font-size: 13px;\n text-align: left;\n transition: background 0.1s;\n}\n.PreferenceApp_categoryItem:hover {\n background: var(--dt-surface-hover);\n}\n.PreferenceApp_categoryItemActive {\n background: var(--dt-surface);\n border-left: 3px solid var(--dt-accent);\n color: var(--dt-accent);\n font-weight: 500;\n padding-left: 13px;\n}\n.PreferenceApp_categoryIcon {\n width: 20px;\n font-size: 15px;\n text-align: center;\n}\n.PreferenceApp_categoryText {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.PreferenceApp_settingsPanel {\n flex: 1;\n min-width: 0;\n overflow-y: auto;\n padding: 0;\n}\n.PreferenceApp_section {\n padding: 20px 24px 8px;\n}\n.PreferenceApp_sectionTitle {\n margin-bottom: 4px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--dt-border);\n color: var(--dt-text-muted);\n font-size: 13px;\n font-weight: 600;\n font-family: var(--font-display, \"Sora\", system-ui, -apple-system, sans-serif);\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n.PreferenceApp_row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n padding: 12px 0;\n border-bottom: 1px solid var(--dt-border-subtle);\n}\n.PreferenceApp_row:last-child {\n border-bottom: none;\n}\n.PreferenceApp_rowInfo {\n flex: 1;\n min-width: 0;\n}\n.PreferenceApp_rowLabel {\n margin-bottom: 2px;\n font-size: 14px;\n font-weight: 500;\n font-family: var(--font-ui, \"Work Sans\", system-ui, -apple-system, sans-serif);\n}\n.PreferenceApp_rowDescription {\n color: var(--dt-text-muted);\n font-size: 12px;\n line-height: 1.4;\n}\n.PreferenceApp_rowRestartBadge {\n display: inline-block;\n margin-left: 6px;\n padding: 1px 5px;\n border-radius: 3px;\n background: var(--dt-warning-subtle);\n color: var(--dt-warning);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.03em;\n text-transform: uppercase;\n}\n.PreferenceApp_rowControl {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n gap: 8px;\n}\n.PreferenceApp_providerGroup {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px 0 18px;\n border-bottom: 1px solid var(--dt-border-subtle);\n}\n.PreferenceApp_providerGroupHeader {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n}\n.PreferenceApp_providerList {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.PreferenceApp_providerCard {\n margin: 0;\n}\n.PreferenceApp_providerCard dt-card {\n display: block;\n margin: 0;\n}\n.PreferenceApp_providerCardBody {\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n.PreferenceApp_providerCardHeader {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n}\n.PreferenceApp_providerCardTitleRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.PreferenceApp_providerCardTitle {\n font-size: 14px;\n font-weight: 600;\n font-family: var(--font-display, \"Sora\", system-ui, -apple-system, sans-serif);\n letter-spacing: -0.01em;\n}\n.PreferenceApp_providerDefaultBadge {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: 999px;\n background: var(--dt-accent-ghost);\n color: var(--dt-accent);\n font-size: 11px;\n font-weight: 600;\n}\n.PreferenceApp_providerCardActions {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: 8px;\n}\n.PreferenceApp_providerActionButtonWrap,\n.PreferenceApp_providerButtonWrap {\n display: inline-flex;\n}\n.PreferenceApp_providerActionButtonWrap dt-button,\n.PreferenceApp_providerButtonWrap dt-button {\n display: inline-flex;\n}\n.PreferenceApp_providerFieldGrid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 12px;\n}\n.PreferenceApp_providerField {\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: 6px;\n}\n.PreferenceApp_providerFieldLabel {\n color: var(--dt-text-muted);\n font-size: 11px;\n font-weight: 600;\n font-family: var(--font-display, \"Sora\", system-ui, -apple-system, sans-serif);\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n.PreferenceApp_providerSelectWrap {\n width: 100%;\n}\n.PreferenceApp_providerSelectWrap dt-select {\n display: block;\n width: 100%;\n}\n.PreferenceApp_selectWrap {\n min-width: 120px;\n}\n.PreferenceApp_selectWrap dt-select {\n display: block;\n min-width: 120px;\n}\n.PreferenceApp_textInput,\n.PreferenceApp_numberInput,\n.PreferenceApp_dropdown {\n padding: 6px 10px;\n border: 1px solid var(--dt-border);\n border-radius: 6px;\n background: var(--dt-surface);\n color: var(--dt-text);\n font-family: var(--font-ui, \"Work Sans\", system-ui, -apple-system, sans-serif);\n font-size: 13px;\n outline: none;\n transition:\n border-color 0.15s,\n box-shadow 0.15s,\n background 0.15s;\n}\n.PreferenceApp_textInput:focus,\n.PreferenceApp_numberInput:focus,\n.PreferenceApp_dropdown:focus {\n border-color: var(--dt-accent);\n box-shadow: 0 0 0 3px var(--dt-accent-ghost);\n}\n.PreferenceApp_textInput {\n width: 220px;\n}\n.PreferenceApp_textInput::placeholder {\n color: var(--dt-text-muted);\n}\n.PreferenceApp_textInputSensitive {\n font-family: var(--font-mono);\n letter-spacing: 0.05em;\n}\n.PreferenceApp_numberInput {\n width: 100px;\n -moz-appearance: textfield;\n}\n.PreferenceApp_numberInput::-webkit-inner-spin-button,\n.PreferenceApp_numberInput::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n.PreferenceApp_dropdown {\n min-width: 120px;\n cursor: pointer;\n}\n.PreferenceApp_colorControl {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.PreferenceApp_colorInput {\n width: 40px;\n height: 36px;\n padding: 2px;\n border: 1px solid var(--dt-border);\n border-radius: 8px;\n background: var(--dt-surface);\n cursor: pointer;\n}\n.PreferenceApp_toggle {\n position: relative;\n width: 42px;\n height: 24px;\n flex-shrink: 0;\n cursor: pointer;\n}\n.PreferenceApp_toggleInput {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n}\n.PreferenceApp_toggleTrack {\n position: absolute;\n inset: 0;\n border: 1px solid var(--dt-border);\n border-radius: 12px;\n background: var(--dt-surface);\n transition: background 0.2s, border-color 0.2s;\n}\n.PreferenceApp_toggleInput:checked + .PreferenceApp_toggleTrack {\n border-color: var(--dt-accent);\n background: var(--dt-accent);\n}\n.PreferenceApp_toggleKnob {\n position: absolute;\n top: 3px;\n left: 3px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--dt-text-on-accent);\n transition: transform 0.2s;\n pointer-events: none;\n}\n.PreferenceApp_toggleInput:checked ~ .PreferenceApp_toggleKnob {\n transform: translateX(18px);\n}\n.PreferenceApp_notification {\n position: fixed;\n bottom: 80px;\n left: 50%;\n z-index: 1000;\n padding: 10px 20px;\n border: 1px solid color-mix(in oklab, var(--dt-warning) 40%, var(--dt-border));\n border-radius: 8px;\n background: color-mix(in oklab, var(--dt-warning) 20%, var(--dt-surface));\n box-shadow: 0 14px 28px var(--dt-shadow-color);\n color: var(--dt-text);\n font-size: 13px;\n font-weight: 500;\n transform: translateX(-50%);\n animation: PreferenceApp_slideUp 0.3s ease-out;\n}\n.PreferenceApp_rootCompact .PreferenceApp_sidebar {\n width: 100%;\n min-width: 0;\n flex-direction: row;\n align-items: center;\n gap: 8px;\n overflow-x: auto;\n overflow-y: visible;\n padding: 10px 12px;\n border-right: none;\n border-bottom: 1px solid var(--dt-border);\n background: color-mix(in oklab, var(--dt-surface) 72%, transparent);\n}\n.PreferenceApp_rootCompact .PreferenceApp_sidebarHeader {\n flex: 0 0 auto;\n padding: 0 10px 0 0;\n border-right: 1px solid var(--dt-border-subtle);\n white-space: nowrap;\n}\n.PreferenceApp_rootCompact .PreferenceApp_categoryItem,\n.PreferenceApp_rootCompact .PreferenceApp_categoryItemActive {\n position: relative;\n width: 40px;\n min-width: 40px;\n height: 40px;\n justify-content: center;\n gap: 0;\n padding: 0;\n border: 1px solid transparent;\n border-radius: 10px;\n flex-shrink: 0;\n}\n.PreferenceApp_rootCompact .PreferenceApp_categoryItemActive {\n border-left: 1px solid color-mix(in oklab, var(--dt-accent) 45%, var(--dt-border));\n background: color-mix(in oklab, var(--dt-accent) 12%, var(--dt-surface));\n box-shadow: 0 0 0 1px var(--dt-accent-ghost) inset;\n padding-left: 0;\n}\n.PreferenceApp_rootCompact .PreferenceApp_settingsPanel {\n padding-bottom: 12px;\n}\n.PreferenceApp_rootCompact .PreferenceApp_section {\n padding: 16px 16px 8px;\n}\n.PreferenceApp_rootCompact .PreferenceApp_row {\n align-items: stretch;\n flex-direction: column;\n gap: 12px;\n}\n.PreferenceApp_rootCompact .PreferenceApp_rowControl {\n width: 100%;\n min-width: 0;\n}\n.PreferenceApp_rootCompact .PreferenceApp_providerGroupHeader,\n.PreferenceApp_rootCompact .PreferenceApp_providerCardHeader {\n flex-direction: column;\n}\n.PreferenceApp_rootCompact .PreferenceApp_providerCardActions {\n justify-content: flex-start;\n}\n.PreferenceApp_rootCompact .PreferenceApp_providerActionButtonWrap,\n.PreferenceApp_rootCompact .PreferenceApp_providerButtonWrap {\n width: 100%;\n}\n.PreferenceApp_rootCompact .PreferenceApp_providerFieldGrid {\n grid-template-columns: 1fr;\n}\n.PreferenceApp_rootCompact .PreferenceApp_textInput,\n.PreferenceApp_rootCompact .PreferenceApp_textInputSensitive,\n.PreferenceApp_rootCompact .PreferenceApp_numberInput,\n.PreferenceApp_rootCompact .PreferenceApp_dropdown,\n.PreferenceApp_rootCompact .PreferenceApp_providerActionButtonWrap dt-button,\n.PreferenceApp_rootCompact .PreferenceApp_providerButtonWrap dt-button {\n width: 100%;\n min-width: 0;\n}\n.PreferenceApp_rootCompact .PreferenceApp_colorControl {\n width: 100%;\n}\n.PreferenceApp_rootCompact .PreferenceApp_colorInput {\n flex: 0 0 44px;\n}\n@keyframes PreferenceApp_slideUp {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n/*# sourceMappingURL=frontend.css.map */\n";
8
+ document.head.appendChild(style);
9
+ })();
10
+
11
+ // src/frontend.tsx
12
+ import { __dtLocalize } from "@desktalk/sdk";
13
+
14
+ // desktalk-global:react
15
+ var _mod = window.React;
16
+ var Children = _mod.Children;
17
+ var Component = _mod.Component;
18
+ var Fragment = _mod.Fragment;
19
+ var Profiler = _mod.Profiler;
20
+ var PureComponent = _mod.PureComponent;
21
+ var StrictMode = _mod.StrictMode;
22
+ var Suspense = _mod.Suspense;
23
+ var cloneElement = _mod.cloneElement;
24
+ var createContext = _mod.createContext;
25
+ var createElement = _mod.createElement;
26
+ var createRef = _mod.createRef;
27
+ var forwardRef = _mod.forwardRef;
28
+ var isValidElement = _mod.isValidElement;
29
+ var lazy = _mod.lazy;
30
+ var memo = _mod.memo;
31
+ var startTransition = _mod.startTransition;
32
+ var useCallback = _mod.useCallback;
33
+ var useContext = _mod.useContext;
34
+ var useDebugValue = _mod.useDebugValue;
35
+ var useDeferredValue = _mod.useDeferredValue;
36
+ var useEffect = _mod.useEffect;
37
+ var useId = _mod.useId;
38
+ var useImperativeHandle = _mod.useImperativeHandle;
39
+ var useInsertionEffect = _mod.useInsertionEffect;
40
+ var useLayoutEffect = _mod.useLayoutEffect;
41
+ var useMemo = _mod.useMemo;
42
+ var useReducer = _mod.useReducer;
43
+ var useRef = _mod.useRef;
44
+ var useState = _mod.useState;
45
+ var useSyncExternalStore = _mod.useSyncExternalStore;
46
+ var useTransition = _mod.useTransition;
47
+ var version = _mod.version;
48
+
49
+ // desktalk-global:react-dom/client
50
+ var _mod2 = window.ReactDOM;
51
+ var createRoot = _mod2.createRoot;
52
+ var hydrateRoot = _mod2.hydrateRoot;
53
+
54
+ // src/frontend.tsx
55
+ import { useCommand as useCommand2, useEvent, MiniAppIdProvider, WindowIdProvider } from "@desktalk/sdk";
56
+
57
+ // src/schema.ts
58
+ var CATEGORIES = ["General", "Server", "AI", "Voice"];
59
+ var DEFAULT_AI_PROVIDER_ID = "openai";
60
+ var AI_PROVIDER_DEFINITIONS = [
61
+ { id: "anthropic", label: "Anthropic", supportsApiKey: true, supportsBaseUrl: false },
62
+ {
63
+ id: "azure-openai-responses",
64
+ label: "Azure OpenAI",
65
+ supportsApiKey: true,
66
+ supportsBaseUrl: true
67
+ },
68
+ { id: DEFAULT_AI_PROVIDER_ID, label: "OpenAI", supportsApiKey: true, supportsBaseUrl: true },
69
+ { id: "google", label: "Google Gemini", supportsApiKey: true, supportsBaseUrl: false },
70
+ {
71
+ id: "mistral",
72
+ label: "Mistral",
73
+ supportsApiKey: true,
74
+ supportsBaseUrl: true
75
+ },
76
+ { id: "groq", label: "Groq", supportsApiKey: true, supportsBaseUrl: true },
77
+ {
78
+ id: "cerebras",
79
+ label: "Cerebras",
80
+ supportsApiKey: true,
81
+ supportsBaseUrl: true
82
+ },
83
+ { id: "xai", label: "xAI", supportsApiKey: true, supportsBaseUrl: true },
84
+ {
85
+ id: "openrouter",
86
+ label: "OpenRouter",
87
+ supportsApiKey: true,
88
+ supportsBaseUrl: true
89
+ },
90
+ {
91
+ id: "vercel-ai-gateway",
92
+ label: "Vercel AI Gateway",
93
+ supportsApiKey: true,
94
+ supportsBaseUrl: true
95
+ },
96
+ { id: "zai", label: "ZAI", supportsApiKey: true, supportsBaseUrl: false },
97
+ { id: "opencode", label: "OpenCode Zen", supportsApiKey: true, supportsBaseUrl: false },
98
+ { id: "opencode-go", label: "OpenCode Go", supportsApiKey: true, supportsBaseUrl: false },
99
+ {
100
+ id: "huggingface",
101
+ label: "Hugging Face",
102
+ supportsApiKey: true,
103
+ supportsBaseUrl: true
104
+ },
105
+ {
106
+ id: "kimi-coding",
107
+ label: "Kimi For Coding",
108
+ supportsApiKey: true,
109
+ supportsBaseUrl: false
110
+ },
111
+ { id: "minimax", label: "MiniMax", supportsApiKey: true, supportsBaseUrl: false },
112
+ {
113
+ id: "minimax-cn",
114
+ label: "MiniMax China",
115
+ supportsApiKey: true,
116
+ supportsBaseUrl: false
117
+ },
118
+ { id: "ollama", label: "Ollama", supportsApiKey: false, supportsBaseUrl: true }
119
+ ];
120
+ var DEFAULT_VOICE_PROVIDER_ID = "openai-whisper";
121
+ var VOICE_PROVIDER_DEFINITIONS = [
122
+ {
123
+ id: DEFAULT_VOICE_PROVIDER_ID,
124
+ label: "OpenAI Whisper",
125
+ supportsApiKey: true,
126
+ supportsBaseUrl: true,
127
+ supportsModel: true,
128
+ supportsAzureDeployment: false,
129
+ supportsAzureApiVersion: false
130
+ },
131
+ {
132
+ id: "azure-openai-whisper",
133
+ label: "Azure OpenAI Whisper",
134
+ supportsApiKey: true,
135
+ supportsBaseUrl: true,
136
+ supportsModel: false,
137
+ supportsAzureDeployment: true,
138
+ supportsAzureApiVersion: true
139
+ }
140
+ ];
141
+ var AI_PROVIDER_IDS = new Set(AI_PROVIDER_DEFINITIONS.map((provider) => provider.id));
142
+ var VOICE_PROVIDER_IDS = new Set(VOICE_PROVIDER_DEFINITIONS.map((provider) => provider.id));
143
+ function getAiProviderDefinition(providerId) {
144
+ return AI_PROVIDER_DEFINITIONS.find((provider) => provider.id === providerId);
145
+ }
146
+ function getAiProviderConfigKeys(providerId) {
147
+ const definition = getAiProviderDefinition(providerId);
148
+ if (!definition) {
149
+ return [];
150
+ }
151
+ const keys = [`ai.providers.${providerId}.model`];
152
+ if (definition.supportsApiKey) {
153
+ keys.push(`ai.providers.${providerId}.apiKey`);
154
+ }
155
+ if (definition.supportsBaseUrl) {
156
+ keys.push(`ai.providers.${providerId}.baseUrl`);
157
+ }
158
+ return keys;
159
+ }
160
+ function parseAiEnabledProviders(value) {
161
+ if (typeof value !== "string") {
162
+ return [DEFAULT_AI_PROVIDER_ID];
163
+ }
164
+ const providers = value.split(",").map((item) => item.trim()).filter(
165
+ (item, index, items) => item && items.indexOf(item) === index && AI_PROVIDER_IDS.has(item)
166
+ );
167
+ return providers.length > 0 ? providers : [DEFAULT_AI_PROVIDER_ID];
168
+ }
169
+ function serializeAiEnabledProviders(providerIds) {
170
+ return parseAiEnabledProviders(providerIds.join(",")).join(",");
171
+ }
172
+ function getVoiceProviderDefinition(providerId) {
173
+ return VOICE_PROVIDER_DEFINITIONS.find((provider) => provider.id === providerId);
174
+ }
175
+ function getVoiceProviderConfigKeys(providerId) {
176
+ const definition = getVoiceProviderDefinition(providerId);
177
+ if (!definition) {
178
+ return [];
179
+ }
180
+ const keys = [];
181
+ if (definition.supportsApiKey) {
182
+ keys.push(`voice.providers.${providerId}.apiKey`);
183
+ }
184
+ if (definition.supportsModel) {
185
+ keys.push(`voice.providers.${providerId}.model`);
186
+ }
187
+ if (definition.supportsBaseUrl) {
188
+ keys.push(`voice.providers.${providerId}.baseUrl`);
189
+ }
190
+ if (definition.supportsAzureDeployment) {
191
+ keys.push(`voice.providers.${providerId}.azureDeployment`);
192
+ }
193
+ if (definition.supportsAzureApiVersion) {
194
+ keys.push(`voice.providers.${providerId}.azureApiVersion`);
195
+ }
196
+ return keys;
197
+ }
198
+ function parseVoiceEnabledProviders(value) {
199
+ if (typeof value !== "string") {
200
+ return [DEFAULT_VOICE_PROVIDER_ID];
201
+ }
202
+ const providers = value.split(",").map((item) => item.trim()).filter(
203
+ (item, index, items) => item && items.indexOf(item) === index && VOICE_PROVIDER_IDS.has(item)
204
+ );
205
+ return providers.length > 0 ? providers : [DEFAULT_VOICE_PROVIDER_ID];
206
+ }
207
+ function serializeVoiceEnabledProviders(providerIds) {
208
+ return parseVoiceEnabledProviders(providerIds.join(",")).join(",");
209
+ }
210
+ function getAiProviderPreferenceSchemas() {
211
+ const schemas = [
212
+ {
213
+ key: "ai.enabledProviders",
214
+ label: "Enabled Providers",
215
+ description: "Ordered list of configured AI providers.",
216
+ type: "string",
217
+ default: DEFAULT_AI_PROVIDER_ID,
218
+ category: "AI"
219
+ },
220
+ {
221
+ key: "ai.defaultProvider",
222
+ label: "Default Provider",
223
+ description: "Provider selected by default for chat and tool execution.",
224
+ type: "string",
225
+ default: DEFAULT_AI_PROVIDER_ID,
226
+ options: AI_PROVIDER_DEFINITIONS.map((provider) => provider.id),
227
+ category: "AI"
228
+ }
229
+ ];
230
+ for (const provider of AI_PROVIDER_DEFINITIONS) {
231
+ schemas.push({
232
+ key: `ai.providers.${provider.id}.model`,
233
+ label: `${provider.label} Model`,
234
+ description: `Model identifier to use when ${provider.label} is selected.`,
235
+ type: "string",
236
+ default: "",
237
+ category: "AI"
238
+ });
239
+ if (provider.supportsApiKey) {
240
+ schemas.push({
241
+ key: `ai.providers.${provider.id}.apiKey`,
242
+ label: `${provider.label} API Key`,
243
+ description: `API key for ${provider.label}.`,
244
+ type: "string",
245
+ default: "",
246
+ category: "AI",
247
+ sensitive: true
248
+ });
249
+ }
250
+ if (provider.supportsBaseUrl) {
251
+ schemas.push({
252
+ key: `ai.providers.${provider.id}.baseUrl`,
253
+ label: `${provider.label} Base URL`,
254
+ description: `Optional custom API base URL for ${provider.label}.`,
255
+ type: "string",
256
+ default: "",
257
+ category: "AI"
258
+ });
259
+ }
260
+ }
261
+ schemas.push({
262
+ key: "ai.maxTokens",
263
+ label: "Max Tokens",
264
+ description: "Maximum tokens per AI response.",
265
+ type: "number",
266
+ default: 4096,
267
+ min: 256,
268
+ max: 128e3,
269
+ category: "AI"
270
+ });
271
+ return schemas;
272
+ }
273
+ var AI_PREFERENCE_SCHEMAS = getAiProviderPreferenceSchemas();
274
+ function getVoiceProviderPreferenceSchemas() {
275
+ const schemas = [
276
+ {
277
+ key: "voice.enabledProviders",
278
+ label: "Enabled Providers",
279
+ description: "Ordered list of configured STT providers.",
280
+ type: "string",
281
+ default: DEFAULT_VOICE_PROVIDER_ID,
282
+ category: "Voice"
283
+ },
284
+ {
285
+ key: "voice.defaultProvider",
286
+ label: "Default Provider",
287
+ description: "Provider selected by default for voice transcription.",
288
+ type: "string",
289
+ default: DEFAULT_VOICE_PROVIDER_ID,
290
+ options: VOICE_PROVIDER_DEFINITIONS.map((provider) => provider.id),
291
+ category: "Voice"
292
+ }
293
+ ];
294
+ for (const provider of VOICE_PROVIDER_DEFINITIONS) {
295
+ if (provider.supportsApiKey) {
296
+ schemas.push({
297
+ key: `voice.providers.${provider.id}.apiKey`,
298
+ label: `${provider.label} API Key`,
299
+ description: `API key for ${provider.label}.`,
300
+ type: "string",
301
+ default: "",
302
+ category: "Voice",
303
+ sensitive: true
304
+ });
305
+ }
306
+ if (provider.supportsModel) {
307
+ schemas.push({
308
+ key: `voice.providers.${provider.id}.model`,
309
+ label: `${provider.label} Model`,
310
+ description: `Model identifier to use when ${provider.label} is selected.`,
311
+ type: "string",
312
+ default: "whisper-1",
313
+ category: "Voice"
314
+ });
315
+ }
316
+ if (provider.supportsBaseUrl) {
317
+ schemas.push({
318
+ key: `voice.providers.${provider.id}.baseUrl`,
319
+ label: `${provider.label} Base URL`,
320
+ description: provider.id === "azure-openai-whisper" ? "Base URL for Azure OpenAI Whisper requests." : `Optional custom API base URL for ${provider.label}.`,
321
+ type: "string",
322
+ default: provider.id === DEFAULT_VOICE_PROVIDER_ID ? "https://api.openai.com/v1" : "",
323
+ category: "Voice"
324
+ });
325
+ }
326
+ if (provider.supportsAzureDeployment) {
327
+ schemas.push({
328
+ key: `voice.providers.${provider.id}.azureDeployment`,
329
+ label: `${provider.label} Deployment`,
330
+ description: "Azure OpenAI deployment name for Whisper transcription.",
331
+ type: "string",
332
+ default: "",
333
+ category: "Voice"
334
+ });
335
+ }
336
+ if (provider.supportsAzureApiVersion) {
337
+ schemas.push({
338
+ key: `voice.providers.${provider.id}.azureApiVersion`,
339
+ label: `${provider.label} API Version`,
340
+ description: "Azure OpenAI API version used for transcription requests.",
341
+ type: "string",
342
+ default: "2024-06-01",
343
+ category: "Voice"
344
+ });
345
+ }
346
+ }
347
+ return schemas;
348
+ }
349
+ var VOICE_PREFERENCE_SCHEMAS = getVoiceProviderPreferenceSchemas();
350
+ var PREFERENCE_SCHEMAS = [
351
+ // ─── General ─────────────────────────────────────────────────────────────
352
+ {
353
+ key: "general.theme",
354
+ label: "Theme",
355
+ description: "UI theme: light or dark.",
356
+ type: "string",
357
+ default: "light",
358
+ options: ["light", "dark"],
359
+ category: "General"
360
+ },
361
+ {
362
+ key: "general.accentColor",
363
+ label: "Accent Color",
364
+ description: "Primary theme color. Accepts hex values or any CSS color string.",
365
+ type: "string",
366
+ default: "#7c6ff7",
367
+ category: "General"
368
+ },
369
+ {
370
+ key: "general.language",
371
+ label: "Language",
372
+ description: "UI language/locale.",
373
+ type: "string",
374
+ default: "en",
375
+ options: ["en", "zh", "ja", "ko", "es", "fr", "de"],
376
+ category: "General"
377
+ },
378
+ {
379
+ key: "general.dataDirectory",
380
+ label: "Data Directory",
381
+ description: "Override the base data directory. Leave empty for platform default (resolved via env-paths).",
382
+ type: "string",
383
+ default: "",
384
+ category: "General",
385
+ requiresRestart: true
386
+ },
387
+ // ─── Server ──────────────────────────────────────────────────────────────
388
+ {
389
+ key: "server.host",
390
+ label: "Host",
391
+ description: "Server bind address.",
392
+ type: "string",
393
+ default: "localhost",
394
+ category: "Server",
395
+ requiresRestart: true
396
+ },
397
+ {
398
+ key: "server.port",
399
+ label: "Port",
400
+ description: "Server listen port.",
401
+ type: "number",
402
+ default: 3e3,
403
+ min: 1,
404
+ max: 65535,
405
+ category: "Server",
406
+ requiresRestart: true
407
+ },
408
+ // ─── AI ──────────────────────────────────────────────────────────────────
409
+ ...AI_PREFERENCE_SCHEMAS,
410
+ // ─── Voice ────────────────────────────────────────────────────────────
411
+ ...VOICE_PREFERENCE_SCHEMAS,
412
+ {
413
+ key: "voice.silenceTimeoutMs",
414
+ label: "Silence Timeout",
415
+ description: "Silence duration (ms) before finalizing an utterance.",
416
+ type: "number",
417
+ default: 800,
418
+ min: 200,
419
+ max: 5e3,
420
+ category: "Voice"
421
+ },
422
+ {
423
+ key: "voice.energyThreshold",
424
+ label: "Energy Threshold",
425
+ description: "RMS energy threshold for voice activity detection (0\u201332767).",
426
+ type: "number",
427
+ default: 500,
428
+ min: 50,
429
+ max: 1e4,
430
+ category: "Voice"
431
+ }
432
+ ];
433
+ function getDefaultConfig() {
434
+ const config = {};
435
+ for (const schema of PREFERENCE_SCHEMAS) {
436
+ config[schema.key] = schema.default;
437
+ }
438
+ return config;
439
+ }
440
+ function getSchema(key) {
441
+ return PREFERENCE_SCHEMAS.find((s) => s.key === key);
442
+ }
443
+ function getSchemasByCategory(category) {
444
+ return PREFERENCE_SCHEMAS.filter((s) => s.category === category);
445
+ }
446
+
447
+ // ../ui/dist/index.js
448
+ var J = `.dt-tooltip-popup {
449
+ position: fixed;
450
+ z-index: 2147483647;
451
+ padding: 6px 10px;
452
+ border: 1px solid var(--dt-accent);
453
+ border-radius: 2px;
454
+ background: var(--dt-surface);
455
+ color: var(--dt-text-secondary);
456
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
457
+ font-size: 12px;
458
+ font-weight: 500;
459
+ line-height: 1.4;
460
+ white-space: nowrap;
461
+ pointer-events: none;
462
+ user-select: none;
463
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
464
+ }
465
+
466
+ /* Tech corner accents */
467
+ .dt-tooltip-popup::before {
468
+ content: '';
469
+ position: absolute;
470
+ top: -1px;
471
+ left: -1px;
472
+ width: 4px;
473
+ height: 4px;
474
+ border-top: 1px solid var(--dt-accent);
475
+ border-left: 1px solid var(--dt-accent);
476
+ }
477
+
478
+ .dt-tooltip-popup::after {
479
+ content: '';
480
+ position: absolute;
481
+ bottom: -1px;
482
+ right: -1px;
483
+ width: 4px;
484
+ height: 4px;
485
+ border-bottom: 1px solid var(--dt-accent);
486
+ border-right: 1px solid var(--dt-accent);
487
+ }
488
+
489
+ /* Arrow styling - tech/minimal */
490
+ .dt-tooltip-popup[data-actual-placement='top'] {
491
+ transform: translateX(-50%);
492
+ }
493
+
494
+ .dt-tooltip-popup[data-actual-placement='top']::before {
495
+ top: auto;
496
+ bottom: -4px;
497
+ left: 50%;
498
+ transform: translateX(-50%);
499
+ width: 0;
500
+ height: 0;
501
+ border: 4px solid transparent;
502
+ border-top-color: var(--dt-accent);
503
+ border-left: none;
504
+ border-right: none;
505
+ }
506
+
507
+ .dt-tooltip-popup[data-actual-placement='bottom'] {
508
+ transform: translateX(-50%);
509
+ }
510
+
511
+ .dt-tooltip-popup[data-actual-placement='bottom']::before {
512
+ bottom: auto;
513
+ top: -4px;
514
+ left: 50%;
515
+ transform: translateX(-50%);
516
+ width: 0;
517
+ height: 0;
518
+ border: 4px solid transparent;
519
+ border-bottom-color: var(--dt-accent);
520
+ border-left: none;
521
+ border-right: none;
522
+ }
523
+
524
+ .dt-tooltip-popup[data-actual-placement='left'] {
525
+ transform: translateY(-50%);
526
+ }
527
+
528
+ .dt-tooltip-popup[data-actual-placement='left']::before {
529
+ left: auto;
530
+ top: 50%;
531
+ right: -4px;
532
+ transform: translateY(-50%);
533
+ width: 0;
534
+ height: 0;
535
+ border: 4px solid transparent;
536
+ border-left-color: var(--dt-accent);
537
+ border-top: none;
538
+ border-bottom: none;
539
+ }
540
+
541
+ .dt-tooltip-popup[data-actual-placement='right'] {
542
+ transform: translateY(-50%);
543
+ }
544
+
545
+ .dt-tooltip-popup[data-actual-placement='right']::before {
546
+ right: auto;
547
+ top: 50%;
548
+ left: -4px;
549
+ transform: translateY(-50%);
550
+ width: 0;
551
+ height: 0;
552
+ border: 4px solid transparent;
553
+ border-right-color: var(--dt-accent);
554
+ border-top: none;
555
+ border-bottom: none;
556
+ }
557
+ `;
558
+ var vt = "dt-tooltip-popup";
559
+ var u = 8;
560
+ var W = false;
561
+ function ft() {
562
+ if (W) return;
563
+ let r = document.createElement("style");
564
+ r.setAttribute("data-dt-tooltip", ""), r.textContent = J, document.head.appendChild(r), W = true;
565
+ }
566
+ var x = class extends HTMLElement {
567
+ _popup = null;
568
+ _showTimeout = null;
569
+ _tooltipId = "";
570
+ _visible = false;
571
+ static get observedAttributes() {
572
+ return ["content", "placement", "delay", "disabled"];
573
+ }
574
+ get content() {
575
+ return this.getAttribute("content") ?? "";
576
+ }
577
+ set content(t) {
578
+ this.setAttribute("content", t);
579
+ }
580
+ get placement() {
581
+ let t = this.getAttribute("placement");
582
+ return t === "bottom" || t === "left" || t === "right" ? t : "top";
583
+ }
584
+ set placement(t) {
585
+ this.setAttribute("placement", t);
586
+ }
587
+ get delay() {
588
+ let t = Number(this.getAttribute("delay"));
589
+ return Number.isFinite(t) && t > 0 ? t : 0;
590
+ }
591
+ set delay(t) {
592
+ this.setAttribute("delay", String(t));
593
+ }
594
+ get disabled() {
595
+ return this.hasAttribute("disabled");
596
+ }
597
+ set disabled(t) {
598
+ t ? this.setAttribute("disabled", "") : this.removeAttribute("disabled");
599
+ }
600
+ constructor() {
601
+ super();
602
+ let t = this.attachShadow({ mode: "open" });
603
+ t.innerHTML = "<slot></slot>", this._tooltipId = `dt-tip-${Math.random().toString(36).slice(2, 9)}`;
604
+ }
605
+ connectedCallback() {
606
+ ft(), this.addEventListener("mouseenter", this._onEnter), this.addEventListener("mouseleave", this._onLeave), this.addEventListener("focusin", this._onEnter), this.addEventListener("focusout", this._onLeave);
607
+ }
608
+ disconnectedCallback() {
609
+ this.removeEventListener("mouseenter", this._onEnter), this.removeEventListener("mouseleave", this._onLeave), this.removeEventListener("focusin", this._onEnter), this.removeEventListener("focusout", this._onLeave), this._hide();
610
+ }
611
+ attributeChangedCallback(t, e, n) {
612
+ t === "disabled" && this.disabled && this._hide(), t === "content" && this._popup && (this._popup.textContent = this.content);
613
+ }
614
+ _onEnter = () => {
615
+ if (this.disabled || !this.content) return;
616
+ this._showTimeout !== null && clearTimeout(this._showTimeout);
617
+ let t = () => {
618
+ this._createPopup(), this._position(), this._visible = true;
619
+ };
620
+ this.delay > 0 ? this._showTimeout = setTimeout(t, this.delay) : t();
621
+ };
622
+ _onLeave = () => {
623
+ this._hide();
624
+ };
625
+ _createPopup() {
626
+ if (this._popup) return;
627
+ let t = document.createElement("div");
628
+ t.className = vt, t.id = this._tooltipId, t.setAttribute("role", "tooltip"), t.textContent = this.content, document.body.appendChild(t), this._popup = t;
629
+ let e = this._getTrigger();
630
+ e && e.setAttribute("aria-describedby", this._tooltipId);
631
+ }
632
+ _hide() {
633
+ if (this._showTimeout !== null && (clearTimeout(this._showTimeout), this._showTimeout = null), this._popup) {
634
+ let t = this._getTrigger();
635
+ t && t.removeAttribute("aria-describedby"), this._popup.remove(), this._popup = null, this._visible = false;
636
+ }
637
+ }
638
+ _getTrigger() {
639
+ let e = this.shadowRoot?.querySelector("slot")?.assignedElements();
640
+ return e && e.length > 0 ? e[0] : null;
641
+ }
642
+ _position() {
643
+ let t = this._popup;
644
+ if (!t) return;
645
+ let e = this.getBoundingClientRect(), n = t.getBoundingClientRect(), i = window.innerWidth, s = window.innerHeight, o = this.placement;
646
+ o === "top" && e.top - n.height - u < 0 ? o = "bottom" : o === "bottom" && e.bottom + n.height + u > s ? o = "top" : o === "left" && e.left - n.width - u < 0 ? o = "right" : o === "right" && e.right + n.width + u > i && (o = "left"), t.setAttribute("data-actual-placement", o);
647
+ let a, d;
648
+ switch (o) {
649
+ case "top":
650
+ d = e.left + e.width / 2, a = e.top - n.height - u;
651
+ break;
652
+ case "bottom":
653
+ d = e.left + e.width / 2, a = e.bottom + u;
654
+ break;
655
+ case "left":
656
+ d = e.left - n.width - u, a = e.top + e.height / 2;
657
+ break;
658
+ case "right":
659
+ d = e.right + u, a = e.top + e.height / 2;
660
+ break;
661
+ }
662
+ t.style.left = `${d}px`, t.style.top = `${a}px`;
663
+ }
664
+ };
665
+ var G = `:host {
666
+ display: block;
667
+ margin-bottom: 12px;
668
+ }
669
+
670
+ .dt-card-inner {
671
+ background: var(--dt-surface);
672
+ border: 1px solid var(--dt-accent);
673
+ border-radius: 2px;
674
+ padding: 12px;
675
+ color: var(--dt-text);
676
+ font-family: var(--font-ui, 'Work Sans', system-ui, sans-serif);
677
+ position: relative;
678
+ height: 100%;
679
+ }
680
+
681
+ /* Corner accents for sci-fi feel */
682
+ .dt-card-inner::before {
683
+ content: '';
684
+ position: absolute;
685
+ top: -1px;
686
+ left: -1px;
687
+ width: 8px;
688
+ height: 8px;
689
+ border-top: 2px solid var(--dt-accent);
690
+ border-left: 2px solid var(--dt-accent);
691
+ }
692
+
693
+ .dt-card-inner::after {
694
+ content: '';
695
+ position: absolute;
696
+ bottom: -1px;
697
+ right: -1px;
698
+ width: 8px;
699
+ height: 8px;
700
+ border-bottom: 2px solid var(--dt-accent);
701
+ border-right: 2px solid var(--dt-accent);
702
+ }
703
+
704
+ :host([variant='outlined']) .dt-card-inner {
705
+ background: transparent;
706
+ border-style: dashed;
707
+ }
708
+
709
+ :host([variant='filled']) .dt-card-inner {
710
+ background: var(--dt-accent-subtle);
711
+ border-style: solid;
712
+ }
713
+
714
+ ::slotted(h1),
715
+ ::slotted(h2),
716
+ ::slotted(h3),
717
+ ::slotted(h4),
718
+ ::slotted(h5),
719
+ ::slotted(h6) {
720
+ color: var(--dt-accent);
721
+ margin: 0 0 6px;
722
+ line-height: 1.2;
723
+ font-family: var(--font-display, 'Sora', system-ui, sans-serif);
724
+ font-weight: 600;
725
+ text-transform: uppercase;
726
+ letter-spacing: 0.1em;
727
+ font-size: 0.85rem;
728
+ }
729
+
730
+ ::slotted(p) {
731
+ color: var(--dt-text-secondary);
732
+ margin: 0 0 6px;
733
+ line-height: 1.4;
734
+ font-family: var(--font-ui, 'Work Sans', system-ui, sans-serif);
735
+ font-size: 0.8125rem;
736
+ }
737
+
738
+ ::slotted(p:last-child) {
739
+ margin-bottom: 0;
740
+ }
741
+ `;
742
+ var _t = "dt-card-inner";
743
+ var w = class extends HTMLElement {
744
+ static get observedAttributes() {
745
+ return ["variant"];
746
+ }
747
+ get variant() {
748
+ let t = this.getAttribute("variant");
749
+ return t === "outlined" || t === "filled" ? t : "default";
750
+ }
751
+ set variant(t) {
752
+ this.setAttribute("variant", t);
753
+ }
754
+ constructor() {
755
+ super();
756
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
757
+ e.textContent = G, t.appendChild(e);
758
+ let n = document.createElement("div");
759
+ n.className = _t, n.innerHTML = "<slot></slot>", t.appendChild(n);
760
+ }
761
+ };
762
+ var j = `.dt-select-menu {
763
+ position: fixed;
764
+ z-index: 2147483646;
765
+ display: flex;
766
+ min-width: 200px;
767
+ max-width: min(300px, 72vw);
768
+ max-height: 240px;
769
+ flex-direction: column;
770
+ overflow-y: auto;
771
+ border: 1px solid var(--dt-accent);
772
+ border-radius: 2px;
773
+ background: var(--dt-surface);
774
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
775
+ opacity: 0;
776
+ pointer-events: none;
777
+ transition: opacity 100ms ease;
778
+ }
779
+
780
+ .dt-select-menu[data-open] {
781
+ opacity: 1;
782
+ pointer-events: auto;
783
+ }
784
+
785
+ .dt-select-option {
786
+ display: flex;
787
+ width: 100%;
788
+ align-items: center;
789
+ justify-content: space-between;
790
+ padding: 8px 10px;
791
+ border: 0;
792
+ border-bottom: 1px solid var(--dt-border-subtle);
793
+ background: transparent;
794
+ color: var(--dt-text);
795
+ font-family: var(
796
+ --font-mono,
797
+ 'SF Mono',
798
+ Monaco,
799
+ 'Cascadia Code',
800
+ 'Roboto Mono',
801
+ Consolas,
802
+ monospace
803
+ );
804
+ font-size: 0.8125rem;
805
+ font-weight: 600;
806
+ letter-spacing: 0.04em;
807
+ text-align: left;
808
+ cursor: pointer;
809
+ transition: all 0.1s ease;
810
+ user-select: none;
811
+ }
812
+
813
+ .dt-select-option:last-child {
814
+ border-bottom: none;
815
+ }
816
+
817
+ .dt-select-option:hover {
818
+ background: var(--dt-accent);
819
+ color: var(--dt-text-on-accent);
820
+ }
821
+
822
+ .dt-select-option.dt-select-option--active {
823
+ background: var(--dt-accent-subtle);
824
+ color: var(--dt-accent);
825
+ }
826
+
827
+ .dt-select-option span {
828
+ overflow: hidden;
829
+ text-overflow: ellipsis;
830
+ white-space: nowrap;
831
+ }
832
+ `;
833
+ var q = `:host {
834
+ display: block;
835
+ width: 100%;
836
+ min-width: 0;
837
+ position: relative;
838
+ }
839
+
840
+ :host([disabled]) .dt-select-trigger {
841
+ cursor: not-allowed;
842
+ opacity: 0.4;
843
+ }
844
+
845
+ .dt-select-trigger {
846
+ display: flex;
847
+ width: 100%;
848
+ min-width: 0;
849
+ max-width: 100%;
850
+ box-sizing: border-box;
851
+ align-items: center;
852
+ gap: 6px;
853
+ padding: 6px 10px;
854
+ border: 1px solid var(--dt-accent);
855
+ border-radius: 2px;
856
+ background: var(--dt-surface);
857
+ color: var(--dt-text);
858
+ font-family: var(
859
+ --font-mono,
860
+ 'SF Mono',
861
+ Monaco,
862
+ 'Cascadia Code',
863
+ 'Roboto Mono',
864
+ Consolas,
865
+ monospace
866
+ );
867
+ font-size: 0.8125rem;
868
+ font-weight: 600;
869
+ letter-spacing: 0.04em;
870
+ line-height: 1;
871
+ cursor: pointer;
872
+ transition: all 0.1s ease;
873
+ user-select: none;
874
+ position: relative;
875
+ }
876
+
877
+ /* Corner accents */
878
+ .dt-select-trigger::before {
879
+ content: '';
880
+ position: absolute;
881
+ top: 0;
882
+ left: 0;
883
+ width: 4px;
884
+ height: 4px;
885
+ border-top: 1px solid var(--dt-accent);
886
+ border-left: 1px solid var(--dt-accent);
887
+ }
888
+
889
+ .dt-select-trigger::after {
890
+ content: '';
891
+ position: absolute;
892
+ bottom: 0;
893
+ right: 0;
894
+ width: 4px;
895
+ height: 4px;
896
+ border-bottom: 1px solid var(--dt-accent);
897
+ border-right: 1px solid var(--dt-accent);
898
+ }
899
+
900
+ .dt-select-trigger:hover:not([disabled]) {
901
+ background: var(--dt-accent);
902
+ color: var(--dt-text-on-accent);
903
+ }
904
+
905
+ .dt-select-trigger:hover:not([disabled])::before,
906
+ .dt-select-trigger:hover:not([disabled])::after {
907
+ border-color: var(--dt-text-on-accent);
908
+ }
909
+
910
+ .dt-select-trigger[aria-expanded='true'] {
911
+ background: var(--dt-accent);
912
+ color: var(--dt-text-on-accent);
913
+ }
914
+
915
+ .dt-select-trigger[aria-expanded='true']::before,
916
+ .dt-select-trigger[aria-expanded='true']::after {
917
+ border-color: var(--dt-text-on-accent);
918
+ }
919
+
920
+ .dt-select-label {
921
+ overflow: hidden;
922
+ text-overflow: ellipsis;
923
+ white-space: nowrap;
924
+ }
925
+
926
+ .dt-select-chevron {
927
+ color: currentColor;
928
+ font-size: 10px;
929
+ transition: transform 140ms ease;
930
+ opacity: 0.7;
931
+ }
932
+
933
+ .dt-select-trigger[aria-expanded='true'] .dt-select-chevron {
934
+ transform: rotate(180deg);
935
+ }
936
+ `;
937
+ var xt = "dt-select-trigger";
938
+ var K = "dt-select-label";
939
+ var wt = "dt-select-chevron";
940
+ var yt = "dt-select-menu";
941
+ var kt = "dt-select-option";
942
+ var Ct = "dt-select-option--active";
943
+ var U = false;
944
+ function Et() {
945
+ if (U) return;
946
+ let r = document.createElement("style");
947
+ r.setAttribute("data-dt-select", ""), r.textContent = j, document.head.appendChild(r), U = true;
948
+ }
949
+ var y = class extends HTMLElement {
950
+ _menu = null;
951
+ _trigger = null;
952
+ _options = [];
953
+ _open = false;
954
+ _menuId = "";
955
+ static get observedAttributes() {
956
+ return ["value", "placeholder", "disabled", "align"];
957
+ }
958
+ get value() {
959
+ return this.getAttribute("value") ?? "";
960
+ }
961
+ set value(t) {
962
+ this.setAttribute("value", t);
963
+ }
964
+ get placeholder() {
965
+ return this.getAttribute("placeholder") ?? "Select\u2026";
966
+ }
967
+ set placeholder(t) {
968
+ this.setAttribute("placeholder", t);
969
+ }
970
+ get disabled() {
971
+ return this.hasAttribute("disabled");
972
+ }
973
+ set disabled(t) {
974
+ t ? this.setAttribute("disabled", "") : this.removeAttribute("disabled");
975
+ }
976
+ get align() {
977
+ return this.getAttribute("align") === "right" ? "right" : "left";
978
+ }
979
+ set align(t) {
980
+ this.setAttribute("align", t);
981
+ }
982
+ get options() {
983
+ return this._options;
984
+ }
985
+ set options(t) {
986
+ this._options = t, this._updateLabel(), this._open && this._renderMenuItems();
987
+ }
988
+ constructor() {
989
+ super();
990
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
991
+ e.textContent = q, t.appendChild(e);
992
+ let n = document.createElement("button");
993
+ n.type = "button", n.className = xt, n.setAttribute("aria-haspopup", "listbox"), n.setAttribute("aria-expanded", "false");
994
+ let i = document.createElement("span");
995
+ i.className = K, n.appendChild(i);
996
+ let s = document.createElement("span");
997
+ s.className = wt, s.setAttribute("aria-hidden", "true"), s.textContent = "\u25BE", n.appendChild(s), t.appendChild(n), this._trigger = n, this._menuId = `dt-sel-${Math.random().toString(36).slice(2, 9)}`;
998
+ }
999
+ connectedCallback() {
1000
+ Et(), this._trigger.addEventListener("click", this._onTriggerClick), this._updateLabel();
1001
+ }
1002
+ disconnectedCallback() {
1003
+ this._trigger.removeEventListener("click", this._onTriggerClick), this._close();
1004
+ }
1005
+ attributeChangedCallback(t) {
1006
+ t === "value" && (this._updateLabel(), this._open && this._renderMenuItems()), t === "placeholder" && !this.value && this._updateLabel(), t === "disabled" && this.disabled && this._close();
1007
+ }
1008
+ _updateLabel() {
1009
+ let t = this._trigger.querySelector(`.${K}`), e = this._options.find((n) => n.value === this.value);
1010
+ t.textContent = e?.label ?? this.placeholder;
1011
+ }
1012
+ _onTriggerClick = () => {
1013
+ this.disabled || (this._open ? this._close() : this._openMenu());
1014
+ };
1015
+ _openMenu() {
1016
+ if (this._open) return;
1017
+ let t = document.createElement("div");
1018
+ t.className = yt, t.id = this._menuId, t.setAttribute("role", "listbox"), document.body.appendChild(t), this._menu = t, this._renderMenuItems(), this._position(), requestAnimationFrame(() => {
1019
+ t.setAttribute("data-open", "");
1020
+ }), this._open = true, this._trigger.setAttribute("aria-expanded", "true"), requestAnimationFrame(() => {
1021
+ document.addEventListener("mousedown", this._onOutsideClick), document.addEventListener("keydown", this._onKeyDown);
1022
+ });
1023
+ }
1024
+ _close() {
1025
+ if (this._open) {
1026
+ if (document.removeEventListener("mousedown", this._onOutsideClick), document.removeEventListener("keydown", this._onKeyDown), this._menu) {
1027
+ this._menu.removeAttribute("data-open");
1028
+ let t = this._menu;
1029
+ setTimeout(() => t.remove(), 140), this._menu = null;
1030
+ }
1031
+ this._open = false, this._trigger.setAttribute("aria-expanded", "false");
1032
+ }
1033
+ }
1034
+ _onOutsideClick = (t) => {
1035
+ let e = t.target;
1036
+ this._menu?.contains(e) || this.contains(e) || this._close();
1037
+ };
1038
+ _onKeyDown = (t) => {
1039
+ t.key === "Escape" && (this._close(), this._trigger.focus());
1040
+ };
1041
+ _renderMenuItems() {
1042
+ let t = this._menu;
1043
+ if (t) {
1044
+ t.innerHTML = "";
1045
+ for (let e of this._options) {
1046
+ let n = document.createElement("button");
1047
+ n.type = "button", n.className = kt, n.setAttribute("role", "option"), n.setAttribute("aria-selected", String(e.value === this.value)), e.value === this.value && n.classList.add(Ct);
1048
+ let i = document.createElement("span");
1049
+ i.textContent = e.label, n.appendChild(i), n.addEventListener("click", () => {
1050
+ this._selectValue(e.value);
1051
+ }), t.appendChild(n);
1052
+ }
1053
+ }
1054
+ }
1055
+ _selectValue(t) {
1056
+ let e = this.value;
1057
+ this.value = t, this._updateLabel(), this._close(), t !== e && this.dispatchEvent(new CustomEvent("dt-change", { detail: { value: t }, bubbles: true, composed: true }));
1058
+ }
1059
+ _position() {
1060
+ let t = this._menu;
1061
+ if (!t) return;
1062
+ let e = this.getBoundingClientRect(), n = 10, i = Math.max(e.width, 240), s = e.bottom + n, o = t.scrollHeight || 260, a = window.innerHeight;
1063
+ if (s + o > a && e.top - o - n > 0 && (s = e.top - o - n), t.style.minWidth = `${i}px`, this.align === "right") {
1064
+ let d = window.innerWidth;
1065
+ t.style.right = `${d - e.right}px`, t.style.left = "auto";
1066
+ } else t.style.left = `${e.left}px`, t.style.right = "auto";
1067
+ t.style.top = `${s}px`;
1068
+ }
1069
+ };
1070
+ var Y = `:host {
1071
+ display: block;
1072
+ margin-bottom: 12px;
1073
+ }
1074
+
1075
+ .dt-grid-inner {
1076
+ display: grid;
1077
+ gap: var(--grid-gap, 12px);
1078
+ grid-template-columns: repeat(auto-fit, minmax(var(--min-width, 220px), 1fr));
1079
+ }
1080
+
1081
+ :host([cols='1']) .dt-grid-inner {
1082
+ grid-template-columns: repeat(1, 1fr);
1083
+ }
1084
+
1085
+ :host([cols='2']) .dt-grid-inner {
1086
+ grid-template-columns: repeat(2, 1fr);
1087
+ }
1088
+
1089
+ :host([cols='3']) .dt-grid-inner {
1090
+ grid-template-columns: repeat(3, 1fr);
1091
+ }
1092
+
1093
+ :host([cols='4']) .dt-grid-inner {
1094
+ grid-template-columns: repeat(4, 1fr);
1095
+ }
1096
+
1097
+ :host([cols='5']) .dt-grid-inner {
1098
+ grid-template-columns: repeat(5, 1fr);
1099
+ }
1100
+
1101
+ :host([cols='6']) .dt-grid-inner {
1102
+ grid-template-columns: repeat(6, 1fr);
1103
+ }
1104
+
1105
+ @media (max-width: 480px) {
1106
+ :host([cols='2']) .dt-grid-inner,
1107
+ :host([cols='3']) .dt-grid-inner,
1108
+ :host([cols='4']) .dt-grid-inner,
1109
+ :host([cols='5']) .dt-grid-inner,
1110
+ :host([cols='6']) .dt-grid-inner {
1111
+ grid-template-columns: 1fr;
1112
+ }
1113
+ }
1114
+
1115
+ :host([gap='0']) .dt-grid-inner {
1116
+ --grid-gap: 0;
1117
+ }
1118
+ :host([gap='4']) .dt-grid-inner {
1119
+ --grid-gap: 4px;
1120
+ }
1121
+ :host([gap='8']) .dt-grid-inner {
1122
+ --grid-gap: 8px;
1123
+ }
1124
+ :host([gap='12']) .dt-grid-inner {
1125
+ --grid-gap: 12px;
1126
+ }
1127
+ :host([gap='16']) .dt-grid-inner {
1128
+ --grid-gap: 16px;
1129
+ }
1130
+ :host([gap='20']) .dt-grid-inner {
1131
+ --grid-gap: 20px;
1132
+ }
1133
+ :host([gap='24']) .dt-grid-inner {
1134
+ --grid-gap: 24px;
1135
+ }
1136
+ :host([gap='32']) .dt-grid-inner {
1137
+ --grid-gap: 32px;
1138
+ }
1139
+
1140
+ :host([min-width='150']) .dt-grid-inner {
1141
+ --min-width: 150px;
1142
+ }
1143
+ :host([min-width='180']) .dt-grid-inner {
1144
+ --min-width: 180px;
1145
+ }
1146
+ :host([min-width='200']) .dt-grid-inner {
1147
+ --min-width: 200px;
1148
+ }
1149
+ :host([min-width='220']) .dt-grid-inner {
1150
+ --min-width: 220px;
1151
+ }
1152
+ :host([min-width='260']) .dt-grid-inner {
1153
+ --min-width: 260px;
1154
+ }
1155
+ :host([min-width='300']) .dt-grid-inner {
1156
+ --min-width: 300px;
1157
+ }
1158
+
1159
+ ::slotted(*) {
1160
+ min-width: 0;
1161
+ }
1162
+ `;
1163
+ var St = "dt-grid-inner";
1164
+ var k = class extends HTMLElement {
1165
+ static get observedAttributes() {
1166
+ return ["cols", "gap", "min-width"];
1167
+ }
1168
+ get cols() {
1169
+ let t = this.getAttribute("cols");
1170
+ return t === "1" || t === "2" || t === "3" || t === "4" || t === "5" || t === "6" ? t : null;
1171
+ }
1172
+ set cols(t) {
1173
+ t === null ? this.removeAttribute("cols") : this.setAttribute("cols", t);
1174
+ }
1175
+ get gap() {
1176
+ let t = this.getAttribute("gap");
1177
+ return t === "0" || t === "4" || t === "8" || t === "12" || t === "20" || t === "24" || t === "32" ? t : "16";
1178
+ }
1179
+ set gap(t) {
1180
+ this.setAttribute("gap", t);
1181
+ }
1182
+ get minWidth() {
1183
+ let t = this.getAttribute("min-width");
1184
+ return t === "150" || t === "180" || t === "200" || t === "260" || t === "300" ? t : "220";
1185
+ }
1186
+ set minWidth(t) {
1187
+ this.setAttribute("min-width", t);
1188
+ }
1189
+ constructor() {
1190
+ super();
1191
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
1192
+ e.textContent = Y, t.appendChild(e);
1193
+ let n = document.createElement("div");
1194
+ n.className = St, n.innerHTML = "<slot></slot>", t.appendChild(n);
1195
+ }
1196
+ };
1197
+ var Z = `:host {
1198
+ display: block;
1199
+ margin-bottom: 12px;
1200
+ }
1201
+
1202
+ .dt-stack-inner {
1203
+ display: flex;
1204
+ flex-direction: var(--flex-direction, column);
1205
+ gap: var(--stack-gap, 12px);
1206
+ align-items: var(--align-items, stretch);
1207
+ }
1208
+
1209
+ :host([direction='column']) .dt-stack-inner {
1210
+ --flex-direction: column;
1211
+ }
1212
+ :host([direction='row']) .dt-stack-inner {
1213
+ --flex-direction: row;
1214
+ }
1215
+
1216
+ :host([gap='0']) .dt-stack-inner {
1217
+ --stack-gap: 0;
1218
+ }
1219
+ :host([gap='4']) .dt-stack-inner {
1220
+ --stack-gap: 4px;
1221
+ }
1222
+ :host([gap='8']) .dt-stack-inner {
1223
+ --stack-gap: 8px;
1224
+ }
1225
+ :host([gap='12']) .dt-stack-inner {
1226
+ --stack-gap: 12px;
1227
+ }
1228
+ :host([gap='16']) .dt-stack-inner {
1229
+ --stack-gap: 16px;
1230
+ }
1231
+ :host([gap='20']) .dt-stack-inner {
1232
+ --stack-gap: 20px;
1233
+ }
1234
+ :host([gap='24']) .dt-stack-inner {
1235
+ --stack-gap: 24px;
1236
+ }
1237
+ :host([gap='32']) .dt-stack-inner {
1238
+ --stack-gap: 32px;
1239
+ }
1240
+
1241
+ :host([align='start']) .dt-stack-inner {
1242
+ --align-items: flex-start;
1243
+ }
1244
+ :host([align='center']) .dt-stack-inner {
1245
+ --align-items: center;
1246
+ }
1247
+ :host([align='end']) .dt-stack-inner {
1248
+ --align-items: flex-end;
1249
+ }
1250
+ :host([align='stretch']) .dt-stack-inner {
1251
+ --align-items: stretch;
1252
+ }
1253
+
1254
+ @media (max-width: 480px) {
1255
+ :host([direction='row']) .dt-stack-inner {
1256
+ --flex-direction: column;
1257
+ }
1258
+ }
1259
+
1260
+ ::slotted(*) {
1261
+ min-width: 0;
1262
+ }
1263
+ `;
1264
+ var Dt = "dt-stack-inner";
1265
+ function $(r) {
1266
+ return r === "row" || r === "horizontal" ? "row" : "column";
1267
+ }
1268
+ var C = class extends HTMLElement {
1269
+ static get observedAttributes() {
1270
+ return ["direction", "gap", "align"];
1271
+ }
1272
+ get direction() {
1273
+ return $(this.getAttribute("direction"));
1274
+ }
1275
+ set direction(t) {
1276
+ this.setAttribute("direction", $(t));
1277
+ }
1278
+ get gap() {
1279
+ let t = this.getAttribute("gap");
1280
+ return t === "0" || t === "4" || t === "8" || t === "12" || t === "20" || t === "24" || t === "32" ? t : "16";
1281
+ }
1282
+ set gap(t) {
1283
+ this.setAttribute("gap", t);
1284
+ }
1285
+ get align() {
1286
+ let t = this.getAttribute("align");
1287
+ return t === "start" || t === "center" || t === "end" ? t : "stretch";
1288
+ }
1289
+ set align(t) {
1290
+ this.setAttribute("align", t);
1291
+ }
1292
+ connectedCallback() {
1293
+ this.#t();
1294
+ }
1295
+ attributeChangedCallback(t) {
1296
+ t === "direction" && this.#t();
1297
+ }
1298
+ constructor() {
1299
+ super();
1300
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
1301
+ e.textContent = Z, t.appendChild(e);
1302
+ let n = document.createElement("div");
1303
+ n.className = Dt, n.innerHTML = "<slot></slot>", t.appendChild(n);
1304
+ }
1305
+ #t() {
1306
+ let t = this.getAttribute("direction"), e = $(t);
1307
+ t !== null && t !== e && this.setAttribute("direction", e);
1308
+ }
1309
+ };
1310
+ var Q = `:host {
1311
+ display: block;
1312
+ }
1313
+
1314
+ .dt-stat-inner {
1315
+ background: var(--dt-surface);
1316
+ border: 1px solid var(--dt-accent);
1317
+ border-radius: 2px;
1318
+ padding: 12px;
1319
+ font-family: var(--font-ui, 'Work Sans', system-ui, sans-serif);
1320
+ display: flex;
1321
+ flex-direction: column;
1322
+ gap: 4px;
1323
+ position: relative;
1324
+ }
1325
+
1326
+ /* Corner accents */
1327
+ .dt-stat-inner::before {
1328
+ content: '';
1329
+ position: absolute;
1330
+ top: 0;
1331
+ left: 0;
1332
+ width: 6px;
1333
+ height: 6px;
1334
+ border-top: 1px solid var(--dt-accent);
1335
+ border-left: 1px solid var(--dt-accent);
1336
+ }
1337
+
1338
+ .dt-stat-inner .label {
1339
+ font-size: 0.625rem;
1340
+ font-weight: 600;
1341
+ color: var(--dt-text-muted);
1342
+ text-transform: uppercase;
1343
+ letter-spacing: 0.12em;
1344
+ }
1345
+
1346
+ .dt-stat-inner .value {
1347
+ font-size: 1.5rem;
1348
+ font-weight: 600;
1349
+ color: var(--dt-accent);
1350
+ line-height: 1.1;
1351
+ white-space: nowrap;
1352
+ overflow: hidden;
1353
+ text-overflow: ellipsis;
1354
+ font-family: var(--font-display, 'Sora', system-ui, sans-serif);
1355
+ }
1356
+
1357
+ .dt-stat-inner .description {
1358
+ font-size: 0.75rem;
1359
+ color: var(--dt-text-secondary);
1360
+ line-height: 1.3;
1361
+ }
1362
+
1363
+ /* Size variants */
1364
+ :host([size='sm']) .dt-stat-inner .value {
1365
+ font-size: 1.125rem;
1366
+ }
1367
+
1368
+ :host([size='sm']) .dt-stat-inner {
1369
+ padding: 8px;
1370
+ }
1371
+
1372
+ :host([size='lg']) .dt-stat-inner .value {
1373
+ font-size: 2rem;
1374
+ }
1375
+
1376
+ :host([size='lg']) .dt-stat-inner {
1377
+ padding: 16px;
1378
+ }
1379
+
1380
+ /* Variant: outlined */
1381
+ :host([variant='outlined']) .dt-stat-inner {
1382
+ background: transparent;
1383
+ border-style: dashed;
1384
+ }
1385
+
1386
+ /* Variant: filled */
1387
+ :host([variant='filled']) .dt-stat-inner {
1388
+ background: var(--dt-accent-subtle);
1389
+ border-style: solid;
1390
+ }
1391
+
1392
+ /* Trend indicators */
1393
+ .dt-stat-inner .trend {
1394
+ display: inline-flex;
1395
+ align-items: center;
1396
+ gap: 3px;
1397
+ font-size: 0.6875rem;
1398
+ font-weight: 600;
1399
+ margin-top: 2px;
1400
+ text-transform: uppercase;
1401
+ letter-spacing: 0.05em;
1402
+ }
1403
+
1404
+ .dt-stat-inner .trend.positive {
1405
+ color: var(--dt-success);
1406
+ }
1407
+
1408
+ .dt-stat-inner .trend.negative {
1409
+ color: var(--dt-danger);
1410
+ }
1411
+
1412
+ .dt-stat-inner .trend.neutral {
1413
+ color: var(--dt-text-muted);
1414
+ }
1415
+ `;
1416
+ var At = "dt-stat-inner";
1417
+ var E = class extends HTMLElement {
1418
+ static get observedAttributes() {
1419
+ return ["label", "value", "description", "size", "variant", "trend", "trend-value"];
1420
+ }
1421
+ _container;
1422
+ _labelEl;
1423
+ _valueEl;
1424
+ _descEl;
1425
+ _trendEl;
1426
+ get label() {
1427
+ return this.getAttribute("label");
1428
+ }
1429
+ set label(t) {
1430
+ t === null ? this.removeAttribute("label") : this.setAttribute("label", t);
1431
+ }
1432
+ get value() {
1433
+ return this.getAttribute("value");
1434
+ }
1435
+ set value(t) {
1436
+ t === null ? this.removeAttribute("value") : this.setAttribute("value", t);
1437
+ }
1438
+ get description() {
1439
+ return this.getAttribute("description");
1440
+ }
1441
+ set description(t) {
1442
+ t === null ? this.removeAttribute("description") : this.setAttribute("description", t);
1443
+ }
1444
+ get size() {
1445
+ let t = this.getAttribute("size");
1446
+ return t === "sm" || t === "lg" ? t : "md";
1447
+ }
1448
+ set size(t) {
1449
+ this.setAttribute("size", t);
1450
+ }
1451
+ get variant() {
1452
+ let t = this.getAttribute("variant");
1453
+ return t === "outlined" || t === "filled" ? t : "default";
1454
+ }
1455
+ set variant(t) {
1456
+ this.setAttribute("variant", t);
1457
+ }
1458
+ get trend() {
1459
+ let t = this.getAttribute("trend");
1460
+ return t === "up" || t === "down" || t === "neutral" ? t : null;
1461
+ }
1462
+ set trend(t) {
1463
+ t === null ? this.removeAttribute("trend") : this.setAttribute("trend", t);
1464
+ }
1465
+ get trendValue() {
1466
+ return this.getAttribute("trend-value");
1467
+ }
1468
+ set trendValue(t) {
1469
+ t === null ? this.removeAttribute("trend-value") : this.setAttribute("trend-value", t);
1470
+ }
1471
+ constructor() {
1472
+ super();
1473
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
1474
+ e.textContent = Q, t.appendChild(e), this._container = document.createElement("div"), this._container.className = At, this._labelEl = document.createElement("div"), this._labelEl.className = "label", this._container.appendChild(this._labelEl), this._valueEl = document.createElement("div"), this._valueEl.className = "value", this._container.appendChild(this._valueEl), this._descEl = document.createElement("div"), this._descEl.className = "description", this._container.appendChild(this._descEl), this._trendEl = document.createElement("div"), this._trendEl.className = "trend", this._container.appendChild(this._trendEl), t.appendChild(this._container), this._render();
1475
+ }
1476
+ attributeChangedCallback(t, e, n) {
1477
+ (t === "label" || t === "value" || t === "description" || t === "size" || t === "variant" || t === "trend" || t === "trend-value") && this._render();
1478
+ }
1479
+ _render() {
1480
+ this._labelEl.textContent = this.label ?? "", this._labelEl.style.display = this.label ? "block" : "none", this._valueEl.textContent = this.value ?? "", this._valueEl.style.display = this.value ? "block" : "none", this._descEl.textContent = this.description ?? "", this._descEl.style.display = this.description ? "block" : "none";
1481
+ let t = this.trend, e = this.trendValue;
1482
+ if (t && e) {
1483
+ this._trendEl.style.display = "inline-flex", this._trendEl.className = `trend ${t === "up" ? "positive" : t === "down" ? "negative" : "neutral"}`;
1484
+ let n = "";
1485
+ t === "up" ? n = "\u2191" : t === "down" ? n = "\u2193" : n = "\u2192", this._trendEl.textContent = `${n} ${e}`;
1486
+ } else this._trendEl.style.display = "none";
1487
+ }
1488
+ };
1489
+ var tt = `:host {
1490
+ display: inline-flex;
1491
+ vertical-align: middle;
1492
+ }
1493
+
1494
+ .dt-badge-inner {
1495
+ display: inline-flex;
1496
+ align-items: center;
1497
+ padding: 2px 6px;
1498
+ border: 1px solid;
1499
+ border-radius: 2px;
1500
+ font-size: 0.6875rem;
1501
+ font-weight: 600;
1502
+ font-family: var(
1503
+ --font-mono,
1504
+ 'SF Mono',
1505
+ Monaco,
1506
+ 'Cascadia Code',
1507
+ 'Roboto Mono',
1508
+ Consolas,
1509
+ monospace
1510
+ );
1511
+ line-height: 1.2;
1512
+ white-space: nowrap;
1513
+ text-transform: uppercase;
1514
+ letter-spacing: 0.1em;
1515
+ }
1516
+
1517
+ /* Variant: accent (default) */
1518
+ :host([variant='accent']) .dt-badge-inner,
1519
+ .dt-badge-inner {
1520
+ background: var(--dt-accent-subtle);
1521
+ border-color: var(--dt-accent);
1522
+ color: var(--dt-accent);
1523
+ }
1524
+
1525
+ /* Variant: success */
1526
+ :host([variant='success']) .dt-badge-inner {
1527
+ background: var(--dt-success-subtle);
1528
+ border-color: var(--dt-success);
1529
+ color: var(--dt-success);
1530
+ }
1531
+
1532
+ /* Variant: danger */
1533
+ :host([variant='danger']) .dt-badge-inner {
1534
+ background: var(--dt-danger-subtle);
1535
+ border-color: var(--dt-danger);
1536
+ color: var(--dt-danger);
1537
+ }
1538
+
1539
+ /* Variant: warning */
1540
+ :host([variant='warning']) .dt-badge-inner {
1541
+ background: var(--dt-warning-subtle);
1542
+ border-color: var(--dt-warning);
1543
+ color: var(--dt-warning);
1544
+ }
1545
+
1546
+ /* Variant: info */
1547
+ :host([variant='info']) .dt-badge-inner {
1548
+ background: var(--dt-info-subtle);
1549
+ border-color: var(--dt-info);
1550
+ color: var(--dt-info);
1551
+ }
1552
+
1553
+ /* Variant: default/neutral */
1554
+ :host([variant='default']) .dt-badge-inner,
1555
+ :host([variant='neutral']) .dt-badge-inner {
1556
+ background: transparent;
1557
+ border-color: var(--dt-border);
1558
+ color: var(--dt-text-secondary);
1559
+ }
1560
+
1561
+ /* Size variants */
1562
+ :host([size='sm']) .dt-badge-inner {
1563
+ padding: 1px 4px;
1564
+ font-size: 0.625rem;
1565
+ }
1566
+
1567
+ :host([size='lg']) .dt-badge-inner {
1568
+ padding: 3px 8px;
1569
+ font-size: 0.75rem;
1570
+ }
1571
+ `;
1572
+ var Mt = "dt-badge-inner";
1573
+ var S = class extends HTMLElement {
1574
+ static get observedAttributes() {
1575
+ return ["variant", "size", "text"];
1576
+ }
1577
+ _container;
1578
+ _slot;
1579
+ get variant() {
1580
+ let t = this.getAttribute("variant");
1581
+ return t === "success" || t === "danger" || t === "warning" || t === "info" || t === "default" || t === "neutral" ? t : "accent";
1582
+ }
1583
+ set variant(t) {
1584
+ this.setAttribute("variant", t);
1585
+ }
1586
+ get size() {
1587
+ let t = this.getAttribute("size");
1588
+ return t === "sm" || t === "lg" ? t : "md";
1589
+ }
1590
+ set size(t) {
1591
+ this.setAttribute("size", t);
1592
+ }
1593
+ get text() {
1594
+ return this.getAttribute("text");
1595
+ }
1596
+ set text(t) {
1597
+ t === null ? this.removeAttribute("text") : this.setAttribute("text", t);
1598
+ }
1599
+ constructor() {
1600
+ super();
1601
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
1602
+ e.textContent = tt, t.appendChild(e), this._container = document.createElement("span"), this._container.className = Mt;
1603
+ let n = this.text;
1604
+ n !== null ? this._container.textContent = n : (this._slot = document.createElement("slot"), this._container.appendChild(this._slot)), t.appendChild(this._container);
1605
+ }
1606
+ attributeChangedCallback(t, e, n) {
1607
+ t === "text" && this._render();
1608
+ }
1609
+ _render() {
1610
+ let t = this.text;
1611
+ t !== null && (this._container.textContent = t);
1612
+ }
1613
+ };
1614
+ var et = `:host {
1615
+ display: inline-flex;
1616
+ vertical-align: middle;
1617
+ }
1618
+
1619
+ .dt-button-inner {
1620
+ display: inline-flex;
1621
+ align-items: center;
1622
+ justify-content: center;
1623
+ gap: 4px;
1624
+ padding: 6px 12px;
1625
+ border: 1px solid var(--dt-accent);
1626
+ border-radius: 2px;
1627
+ font-size: 0.8125rem;
1628
+ font-weight: 600;
1629
+ font-family: var(--font-ui, 'Work Sans', system-ui, sans-serif);
1630
+ line-height: 1.2;
1631
+ cursor: pointer;
1632
+ transition: all 0.1s ease;
1633
+ background: var(--dt-surface);
1634
+ color: var(--dt-accent);
1635
+ text-transform: uppercase;
1636
+ letter-spacing: 0.08em;
1637
+ position: relative;
1638
+ }
1639
+
1640
+ /* Corner accents */
1641
+ .dt-button-inner::before {
1642
+ content: '';
1643
+ position: absolute;
1644
+ top: 0;
1645
+ left: 0;
1646
+ width: 4px;
1647
+ height: 4px;
1648
+ border-top: 1px solid var(--dt-accent);
1649
+ border-left: 1px solid var(--dt-accent);
1650
+ }
1651
+
1652
+ .dt-button-inner::after {
1653
+ content: '';
1654
+ position: absolute;
1655
+ bottom: 0;
1656
+ right: 0;
1657
+ width: 4px;
1658
+ height: 4px;
1659
+ border-bottom: 1px solid var(--dt-accent);
1660
+ border-right: 1px solid var(--dt-accent);
1661
+ }
1662
+
1663
+ .dt-button-inner:hover:not(:disabled) {
1664
+ background: var(--dt-accent);
1665
+ color: var(--dt-text-on-accent);
1666
+ }
1667
+
1668
+ .dt-button-inner:hover:not(:disabled)::before,
1669
+ .dt-button-inner:hover:not(:disabled)::after {
1670
+ border-color: var(--dt-text-on-accent);
1671
+ }
1672
+
1673
+ .dt-button-inner:active:not(:disabled) {
1674
+ background: var(--dt-accent-active);
1675
+ }
1676
+
1677
+ .dt-button-inner:disabled {
1678
+ opacity: 0.4;
1679
+ cursor: not-allowed;
1680
+ border-color: var(--dt-border);
1681
+ color: var(--dt-text-muted);
1682
+ }
1683
+
1684
+ .dt-button-inner:disabled::before,
1685
+ .dt-button-inner:disabled::after {
1686
+ border-color: var(--dt-border);
1687
+ }
1688
+
1689
+ /* Variant: primary - filled accent */
1690
+ :host([variant='primary']) .dt-button-inner {
1691
+ background: var(--dt-accent);
1692
+ color: var(--dt-text-on-accent);
1693
+ }
1694
+
1695
+ :host([variant='primary']) .dt-button-inner:hover:not(:disabled) {
1696
+ background: var(--dt-accent-hover);
1697
+ }
1698
+
1699
+ /* Variant: secondary - outlined */
1700
+ :host([variant='secondary']) .dt-button-inner {
1701
+ background: transparent;
1702
+ border-color: var(--dt-border);
1703
+ color: var(--dt-text);
1704
+ }
1705
+
1706
+ :host([variant='secondary']) .dt-button-inner:hover:not(:disabled) {
1707
+ background: var(--dt-surface-hover);
1708
+ border-color: var(--dt-accent);
1709
+ color: var(--dt-accent);
1710
+ }
1711
+
1712
+ /* Variant: ghost - minimal */
1713
+ :host([variant='ghost']) .dt-button-inner {
1714
+ background: transparent;
1715
+ border-color: transparent;
1716
+ color: var(--dt-text-secondary);
1717
+ }
1718
+
1719
+ :host([variant='ghost']) .dt-button-inner:hover:not(:disabled) {
1720
+ background: var(--dt-surface);
1721
+ border-color: var(--dt-border);
1722
+ color: var(--dt-text);
1723
+ }
1724
+
1725
+ :host([variant='ghost']) .dt-button-inner::before,
1726
+ :host([variant='ghost']) .dt-button-inner::after {
1727
+ display: none;
1728
+ }
1729
+
1730
+ /* Variant: danger */
1731
+ :host([variant='danger']) .dt-button-inner {
1732
+ background: transparent;
1733
+ border-color: var(--dt-danger);
1734
+ color: var(--dt-danger);
1735
+ }
1736
+
1737
+ :host([variant='danger']) .dt-button-inner:hover:not(:disabled) {
1738
+ background: var(--dt-danger);
1739
+ color: var(--dt-text-on-accent);
1740
+ }
1741
+
1742
+ :host([variant='danger']) .dt-button-inner::before,
1743
+ :host([variant='danger']) .dt-button-inner::after {
1744
+ border-color: var(--dt-danger);
1745
+ }
1746
+
1747
+ :host([variant='danger']) .dt-button-inner:hover:not(:disabled)::before,
1748
+ :host([variant='danger']) .dt-button-inner:hover:not(:disabled)::after {
1749
+ border-color: var(--dt-text-on-accent);
1750
+ }
1751
+
1752
+ /* Size: sm */
1753
+ :host([size='sm']) .dt-button-inner {
1754
+ padding: 4px 8px;
1755
+ font-size: 0.75rem;
1756
+ }
1757
+
1758
+ /* Size: lg */
1759
+ :host([size='lg']) .dt-button-inner {
1760
+ padding: 8px 16px;
1761
+ font-size: 0.875rem;
1762
+ }
1763
+
1764
+ :host([fullwidth]) .dt-button-inner {
1765
+ width: 100%;
1766
+ }
1767
+
1768
+ ::slotted([slot='icon']) {
1769
+ display: inline-flex;
1770
+ width: 1em;
1771
+ height: 1em;
1772
+ }
1773
+ `;
1774
+ var Tt = "dt-button-inner";
1775
+ var D = class extends HTMLElement {
1776
+ static get observedAttributes() {
1777
+ return ["variant", "size", "disabled", "fullwidth", "type"];
1778
+ }
1779
+ _button;
1780
+ _slot;
1781
+ get variant() {
1782
+ let t = this.getAttribute("variant");
1783
+ return t === "secondary" || t === "ghost" || t === "danger" ? t : "primary";
1784
+ }
1785
+ set variant(t) {
1786
+ this.setAttribute("variant", t);
1787
+ }
1788
+ get size() {
1789
+ let t = this.getAttribute("size");
1790
+ return t === "sm" || t === "lg" ? t : "md";
1791
+ }
1792
+ set size(t) {
1793
+ this.setAttribute("size", t);
1794
+ }
1795
+ get disabled() {
1796
+ return this.hasAttribute("disabled");
1797
+ }
1798
+ set disabled(t) {
1799
+ t ? this.setAttribute("disabled", "") : this.removeAttribute("disabled");
1800
+ }
1801
+ get fullwidth() {
1802
+ return this.hasAttribute("fullwidth");
1803
+ }
1804
+ set fullwidth(t) {
1805
+ t ? this.setAttribute("fullwidth", "") : this.removeAttribute("fullwidth");
1806
+ }
1807
+ get type() {
1808
+ let t = this.getAttribute("type");
1809
+ return t === "submit" || t === "reset" ? t : "button";
1810
+ }
1811
+ set type(t) {
1812
+ this.setAttribute("type", t);
1813
+ }
1814
+ constructor() {
1815
+ super();
1816
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
1817
+ e.textContent = et, t.appendChild(e), this._button = document.createElement("button"), this._button.className = Tt, this._button.type = this.type, this._button.disabled = this.disabled, this._slot = document.createElement("slot"), this._button.appendChild(this._slot), t.appendChild(this._button);
1818
+ }
1819
+ attributeChangedCallback(t, e, n) {
1820
+ switch (t) {
1821
+ case "disabled":
1822
+ this._button.disabled = this.disabled;
1823
+ break;
1824
+ case "type":
1825
+ this._button.type = this.type;
1826
+ break;
1827
+ }
1828
+ }
1829
+ };
1830
+ var nt = `:host {
1831
+ display: block;
1832
+ }
1833
+
1834
+ .dt-divider-inner {
1835
+ border: none;
1836
+ margin: 0;
1837
+ flex-shrink: 0;
1838
+ }
1839
+
1840
+ /* Horizontal (default) */
1841
+ :host([direction='horizontal']) .dt-divider-inner,
1842
+ .dt-divider-inner {
1843
+ width: 100%;
1844
+ height: 1px;
1845
+ background: var(--dt-accent);
1846
+ opacity: 0.5;
1847
+ }
1848
+
1849
+ /* Vertical */
1850
+ :host([direction='vertical']) .dt-divider-inner {
1851
+ width: 1px;
1852
+ height: 100%;
1853
+ min-height: 1em;
1854
+ background: var(--dt-accent);
1855
+ opacity: 0.5;
1856
+ }
1857
+
1858
+ /* Style variants */
1859
+ :host([style-variant='subtle']) .dt-divider-inner {
1860
+ background: var(--dt-border);
1861
+ opacity: 1;
1862
+ }
1863
+
1864
+ :host([style-variant='strong']) .dt-divider-inner {
1865
+ background: var(--dt-accent);
1866
+ opacity: 1;
1867
+ height: 2px;
1868
+ }
1869
+
1870
+ :host([direction='vertical'][style-variant='strong']) .dt-divider-inner {
1871
+ width: 2px;
1872
+ height: 100%;
1873
+ }
1874
+
1875
+ /* Spacing */
1876
+ :host([spacing='sm']) .dt-divider-inner {
1877
+ margin: 6px 0;
1878
+ }
1879
+ :host([spacing='md']) .dt-divider-inner {
1880
+ margin: 12px 0;
1881
+ }
1882
+ :host([spacing='lg']) .dt-divider-inner {
1883
+ margin: 18px 0;
1884
+ }
1885
+
1886
+ :host([direction='vertical'][spacing='sm']) .dt-divider-inner {
1887
+ margin: 0 6px;
1888
+ }
1889
+ :host([direction='vertical'][spacing='md']) .dt-divider-inner {
1890
+ margin: 0 12px;
1891
+ }
1892
+ :host([direction='vertical'][spacing='lg']) .dt-divider-inner {
1893
+ margin: 0 18px;
1894
+ }
1895
+ `;
1896
+ var zt = "dt-divider-inner";
1897
+ var A = class extends HTMLElement {
1898
+ static get observedAttributes() {
1899
+ return ["direction", "style-variant", "spacing"];
1900
+ }
1901
+ get direction() {
1902
+ return this.getAttribute("direction") === "vertical" ? "vertical" : "horizontal";
1903
+ }
1904
+ set direction(t) {
1905
+ this.setAttribute("direction", t);
1906
+ }
1907
+ get styleVariant() {
1908
+ let t = this.getAttribute("style-variant");
1909
+ return t === "subtle" || t === "strong" ? t : "default";
1910
+ }
1911
+ set styleVariant(t) {
1912
+ this.setAttribute("style-variant", t);
1913
+ }
1914
+ get spacing() {
1915
+ let t = this.getAttribute("spacing");
1916
+ return t === "sm" || t === "md" || t === "lg" ? t : null;
1917
+ }
1918
+ set spacing(t) {
1919
+ t === null ? this.removeAttribute("spacing") : this.setAttribute("spacing", t);
1920
+ }
1921
+ constructor() {
1922
+ super();
1923
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
1924
+ e.textContent = nt, t.appendChild(e);
1925
+ let n = document.createElement("hr");
1926
+ n.className = zt, t.appendChild(n);
1927
+ }
1928
+ };
1929
+ var rt = `:host {
1930
+ display: block;
1931
+ min-height: 180px;
1932
+ color: var(--dt-text);
1933
+ font-family: var(
1934
+ --font-mono,
1935
+ 'SF Mono',
1936
+ Monaco,
1937
+ 'Cascadia Code',
1938
+ 'Roboto Mono',
1939
+ Consolas,
1940
+ monospace
1941
+ );
1942
+ }
1943
+
1944
+ .dt-table-view {
1945
+ display: flex;
1946
+ flex-direction: column;
1947
+ min-height: inherit;
1948
+ height: 100%;
1949
+ overflow: hidden;
1950
+ background: var(--dt-surface);
1951
+ border: 1px solid var(--dt-border);
1952
+ border-radius: 2px;
1953
+ position: relative;
1954
+ }
1955
+
1956
+ .dt-table-view::before,
1957
+ .dt-table-view::after {
1958
+ content: '';
1959
+ position: absolute;
1960
+ width: 8px;
1961
+ height: 8px;
1962
+ pointer-events: none;
1963
+ z-index: 3;
1964
+ }
1965
+
1966
+ .dt-table-view::before {
1967
+ top: -1px;
1968
+ left: -1px;
1969
+ border-top: 2px solid var(--dt-accent);
1970
+ border-left: 2px solid var(--dt-accent);
1971
+ }
1972
+
1973
+ .dt-table-view::after {
1974
+ right: -1px;
1975
+ bottom: -1px;
1976
+ border-right: 2px solid var(--dt-accent);
1977
+ border-bottom: 2px solid var(--dt-accent);
1978
+ }
1979
+
1980
+ .dt-table-scroll {
1981
+ min-height: inherit;
1982
+ height: 100%;
1983
+ overflow: auto;
1984
+ }
1985
+
1986
+ .dt-table-header,
1987
+ .dt-table-row {
1988
+ display: grid;
1989
+ grid-template-columns: var(--dt-table-columns, minmax(0, 1fr));
1990
+ min-width: fit-content;
1991
+ }
1992
+
1993
+ .dt-table-header {
1994
+ position: sticky;
1995
+ top: 0;
1996
+ z-index: 2;
1997
+ background: color-mix(in srgb, var(--dt-surface) 88%, var(--dt-accent) 12%);
1998
+ border-bottom: 1px solid var(--dt-border);
1999
+ }
2000
+
2001
+ .dt-table-header-cell,
2002
+ .dt-table-cell {
2003
+ min-width: 0;
2004
+ padding: 10px 12px;
2005
+ overflow: hidden;
2006
+ text-overflow: ellipsis;
2007
+ white-space: nowrap;
2008
+ font-size: 0.8125rem;
2009
+ }
2010
+
2011
+ .dt-table-header-cell {
2012
+ color: var(--dt-accent);
2013
+ font-size: 0.75rem;
2014
+ font-weight: 600;
2015
+ letter-spacing: 0.1em;
2016
+ text-transform: uppercase;
2017
+ }
2018
+
2019
+ .dt-table-header-cell--sortable {
2020
+ cursor: pointer;
2021
+ user-select: none;
2022
+ }
2023
+
2024
+ .dt-table-header-cell--sortable:hover {
2025
+ background: var(--dt-surface-hover);
2026
+ }
2027
+
2028
+ .dt-table-header-label {
2029
+ display: inline-flex;
2030
+ align-items: center;
2031
+ gap: 6px;
2032
+ }
2033
+
2034
+ .dt-table-sort-indicator {
2035
+ color: var(--dt-text-secondary);
2036
+ font-size: 0.7rem;
2037
+ }
2038
+
2039
+ .dt-table-body {
2040
+ position: relative;
2041
+ }
2042
+
2043
+ .dt-table-canvas {
2044
+ position: relative;
2045
+ }
2046
+
2047
+ .dt-table-row {
2048
+ position: absolute;
2049
+ left: 0;
2050
+ right: 0;
2051
+ border-bottom: 1px solid var(--dt-border-subtle);
2052
+ }
2053
+
2054
+ .dt-table-row--clickable {
2055
+ cursor: pointer;
2056
+ }
2057
+
2058
+ .dt-table-row--clickable:hover {
2059
+ background: var(--dt-surface-hover);
2060
+ }
2061
+
2062
+ :host([striped]) .dt-table-row:nth-child(even) {
2063
+ background: color-mix(in srgb, var(--dt-surface) 92%, var(--dt-accent) 8%);
2064
+ }
2065
+
2066
+ :host([bordered]) .dt-table-header-cell,
2067
+ :host([bordered]) .dt-table-cell {
2068
+ border-right: 1px solid var(--dt-border-subtle);
2069
+ }
2070
+
2071
+ :host([bordered]) .dt-table-header-cell:last-child,
2072
+ :host([bordered]) .dt-table-cell:last-child {
2073
+ border-right: 0;
2074
+ }
2075
+
2076
+ .dt-table-cell[data-align='center'],
2077
+ .dt-table-header-cell[data-align='center'] {
2078
+ text-align: center;
2079
+ }
2080
+
2081
+ .dt-table-cell[data-align='right'],
2082
+ .dt-table-header-cell[data-align='right'] {
2083
+ text-align: right;
2084
+ }
2085
+
2086
+ .dt-table-empty {
2087
+ display: flex;
2088
+ align-items: center;
2089
+ justify-content: center;
2090
+ min-height: 140px;
2091
+ padding: 20px;
2092
+ color: var(--dt-text-muted);
2093
+ text-transform: uppercase;
2094
+ letter-spacing: 0.08em;
2095
+ font-size: 0.75rem;
2096
+ }
2097
+ `;
2098
+ function Lt(r) {
2099
+ return r == null || r === false ? null : r === true ? "" : String(r);
2100
+ }
2101
+ function Ht(r, t) {
2102
+ let e = r.querySelectorAll("*");
2103
+ for (let n of e) {
2104
+ let i = n.getAttribute("data-field");
2105
+ if (i) {
2106
+ let s = t[i];
2107
+ n.textContent = s == null ? "" : String(s);
2108
+ }
2109
+ for (let s of n.getAttributeNames()) {
2110
+ if (s === "data-field" || !s.startsWith("data-field-")) continue;
2111
+ let o = s.slice(11);
2112
+ if (!o) continue;
2113
+ let a = n.getAttribute(s);
2114
+ if (!a) continue;
2115
+ let d = Lt(t[a]);
2116
+ d === null ? n.removeAttribute(o) : n.setAttribute(o, d);
2117
+ }
2118
+ }
2119
+ }
2120
+ function M(r, t) {
2121
+ let e = r.content.cloneNode(true);
2122
+ return Ht(e, t), e;
2123
+ }
2124
+ var m = class {
2125
+ _count = 0;
2126
+ _estimateSize = 56;
2127
+ _overscan = 5;
2128
+ _fixedSize = null;
2129
+ _viewportHeight = 0;
2130
+ _scrollTop = 0;
2131
+ _sizes = /* @__PURE__ */ new Map();
2132
+ constructor(t = {}) {
2133
+ this._count = t.count ?? 0, this._estimateSize = t.estimateSize ?? 56, this._overscan = t.overscan ?? 5, this._fixedSize = t.fixedSize ?? null;
2134
+ }
2135
+ setCount(t) {
2136
+ this._count = Math.max(0, t);
2137
+ for (let e of this._sizes.keys()) e >= this._count && this._sizes.delete(e);
2138
+ }
2139
+ setViewportHeight(t) {
2140
+ this._viewportHeight = Math.max(0, t);
2141
+ }
2142
+ setScrollTop(t) {
2143
+ this._scrollTop = Math.max(0, t);
2144
+ }
2145
+ setEstimateSize(t) {
2146
+ this._estimateSize = Math.max(1, t);
2147
+ }
2148
+ setFixedSize(t) {
2149
+ this._fixedSize = t && t > 0 ? t : null;
2150
+ }
2151
+ resetMeasurements() {
2152
+ this._sizes.clear();
2153
+ }
2154
+ measure(t, e) {
2155
+ if (this._fixedSize !== null || t < 0 || t >= this._count) return 0;
2156
+ let n = Math.max(1, Math.round(e)), i = this._sizes.get(t);
2157
+ return i === n ? 0 : (this._sizes.set(t, n), this.getOffset(t + 1) <= this._scrollTop ? n - (i ?? this._estimateSize) : 0);
2158
+ }
2159
+ getOffset(t) {
2160
+ if (t <= 0) return 0;
2161
+ let e = Math.min(t, this._count);
2162
+ if (this._fixedSize !== null) return e * this._fixedSize;
2163
+ let n = 0;
2164
+ for (let i = 0; i < e; i += 1) n += this._sizes.get(i) ?? this._estimateSize;
2165
+ return n;
2166
+ }
2167
+ getTotalHeight() {
2168
+ return this.getOffset(this._count);
2169
+ }
2170
+ getRange() {
2171
+ if (this._count === 0) return { start: 0, end: 0, paddingTop: 0, paddingBottom: 0, totalHeight: 0 };
2172
+ if (this._fixedSize !== null) {
2173
+ let d = Math.max(1, Math.ceil(this._viewportHeight / this._fixedSize)), c = Math.max(0, Math.floor(this._scrollTop / this._fixedSize) - this._overscan), l = Math.min(this._count, c + d + this._overscan * 2), f = c * this._fixedSize, _ = this._count * this._fixedSize, h = Math.max(0, _ - f - (l - c) * this._fixedSize);
2174
+ return { start: c, end: l, paddingTop: f, paddingBottom: h, totalHeight: _ };
2175
+ }
2176
+ let t = 0, e = 0;
2177
+ for (; t < this._count; ) {
2178
+ let d = this._sizes.get(t) ?? this._estimateSize;
2179
+ if (e + d > this._scrollTop) break;
2180
+ e += d, t += 1;
2181
+ }
2182
+ t = Math.max(0, t - this._overscan);
2183
+ let n = this.getOffset(t), i = t, s = 0;
2184
+ for (; i < this._count && s < this._viewportHeight; ) s += this._sizes.get(i) ?? this._estimateSize, i += 1;
2185
+ i = Math.min(this._count, i + this._overscan);
2186
+ let o = this.getTotalHeight(), a = Math.max(0, o - this.getOffset(i));
2187
+ return { start: t, end: i, paddingTop: n, paddingBottom: a, totalHeight: o };
2188
+ }
2189
+ };
2190
+ function Rt(r) {
2191
+ return r && typeof r == "object" ? r : { value: r };
2192
+ }
2193
+ function Vt(r) {
2194
+ return r === "center" || r === "right" ? r : "left";
2195
+ }
2196
+ var b = class extends HTMLElement {
2197
+ static get observedAttributes() {
2198
+ return ["field", "header", "width", "min-width", "align"];
2199
+ }
2200
+ get field() {
2201
+ return this.getAttribute("field") ?? "";
2202
+ }
2203
+ get header() {
2204
+ return this.getAttribute("header") ?? this.field;
2205
+ }
2206
+ get width() {
2207
+ return this.getAttribute("width") ?? "auto";
2208
+ }
2209
+ get minWidth() {
2210
+ return this.getAttribute("min-width") ?? "0";
2211
+ }
2212
+ get align() {
2213
+ return Vt(this.getAttribute("align"));
2214
+ }
2215
+ connectedCallback() {
2216
+ this.hidden = true;
2217
+ }
2218
+ attributeChangedCallback() {
2219
+ this.dispatchEvent(new CustomEvent("dt-column-change", { bubbles: true, composed: true }));
2220
+ }
2221
+ };
2222
+ var T = class extends HTMLElement {
2223
+ _rows = [];
2224
+ _columns = [];
2225
+ _virtualizer = new m({ estimateSize: 40, overscan: 5, fixedSize: 40 });
2226
+ _root;
2227
+ _scroll;
2228
+ _header;
2229
+ _body;
2230
+ _canvas;
2231
+ _emptyState;
2232
+ _resizeObserver = null;
2233
+ _mutationObserver = null;
2234
+ _sortField = null;
2235
+ _sortDirection = "asc";
2236
+ static get observedAttributes() {
2237
+ return ["row-height", "sortable", "striped", "bordered", "empty-text"];
2238
+ }
2239
+ get rows() {
2240
+ return this._rows;
2241
+ }
2242
+ set rows(t) {
2243
+ this._rows = Array.isArray(t) ? t : [], this._virtualizer.setCount(this._rows.length), this._render();
2244
+ }
2245
+ get rowHeight() {
2246
+ let t = Number(this.getAttribute("row-height") ?? "40");
2247
+ return Number.isFinite(t) && t > 0 ? t : 40;
2248
+ }
2249
+ set rowHeight(t) {
2250
+ this.setAttribute("row-height", String(t));
2251
+ }
2252
+ get sortable() {
2253
+ return this.hasAttribute("sortable");
2254
+ }
2255
+ get emptyText() {
2256
+ return this.getAttribute("empty-text") ?? "No data";
2257
+ }
2258
+ constructor() {
2259
+ super();
2260
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
2261
+ e.textContent = rt, t.appendChild(e), this._root = document.createElement("div"), this._root.className = "dt-table-view", this._scroll = document.createElement("div"), this._scroll.className = "dt-table-scroll", this._scroll.addEventListener("scroll", this._onScroll, { passive: true }), this._header = document.createElement("div"), this._header.className = "dt-table-header", this._body = document.createElement("div"), this._body.className = "dt-table-body", this._canvas = document.createElement("div"), this._canvas.className = "dt-table-canvas", this._emptyState = document.createElement("div"), this._emptyState.className = "dt-table-empty", this._body.append(this._canvas, this._emptyState), this._scroll.append(this._header, this._body), this._root.appendChild(this._scroll), t.appendChild(this._root);
2262
+ }
2263
+ connectedCallback() {
2264
+ this._virtualizer.setFixedSize(this.rowHeight), this._virtualizer.setEstimateSize(this.rowHeight), this._syncColumns(), this._resizeObserver = new ResizeObserver((t) => {
2265
+ for (let e of t) if (e.target === this._scroll) {
2266
+ let n = this._header.offsetHeight;
2267
+ this._virtualizer.setViewportHeight(Math.max(0, e.contentRect.height - n)), this._render();
2268
+ }
2269
+ }), this._resizeObserver.observe(this._scroll), this._mutationObserver = new MutationObserver(() => {
2270
+ this._syncColumns(), this._render();
2271
+ }), this._mutationObserver.observe(this, { childList: true, subtree: true, attributes: true, attributeFilter: ["field", "header", "width", "min-width", "align"] }), this._virtualizer.setCount(this._rows.length), this._virtualizer.setViewportHeight(Math.max(0, this._scroll.clientHeight - this._header.offsetHeight)), this._render();
2272
+ }
2273
+ disconnectedCallback() {
2274
+ this._scroll.removeEventListener("scroll", this._onScroll), this._resizeObserver?.disconnect(), this._mutationObserver?.disconnect(), this._resizeObserver = null, this._mutationObserver = null;
2275
+ }
2276
+ attributeChangedCallback(t) {
2277
+ t === "row-height" && (this._virtualizer.setFixedSize(this.rowHeight), this._virtualizer.setEstimateSize(this.rowHeight)), this._render();
2278
+ }
2279
+ _onScroll = () => {
2280
+ this._virtualizer.setScrollTop(Math.max(0, this._scroll.scrollTop - this._header.offsetHeight)), this._renderBody();
2281
+ };
2282
+ _syncColumns() {
2283
+ this._columns = Array.from(this.children).filter((t) => t instanceof b).map((t) => ({ field: t.field, header: t.header, width: t.width, minWidth: t.minWidth, align: t.align, template: Array.from(t.children).find((e) => e instanceof HTMLTemplateElement) ?? null })).filter((t) => t.field);
2284
+ }
2285
+ _render() {
2286
+ if (!this.isConnected) return;
2287
+ this._emptyState.textContent = this.emptyText;
2288
+ let t = this._columns.length > 0 ? this._columns.map((e) => this._toGridColumn(e)).join(" ") : "minmax(0, 1fr)";
2289
+ this._header.style.setProperty("--dt-table-columns", t), this._canvas.style.setProperty("--dt-table-columns", t), this._renderHeader(), this._renderBody();
2290
+ }
2291
+ _renderHeader() {
2292
+ let t = document.createDocumentFragment();
2293
+ for (let e of this._columns) {
2294
+ let n = document.createElement("div");
2295
+ n.className = "dt-table-header-cell", n.dataset.align = e.align, this.sortable && (n.classList.add("dt-table-header-cell--sortable"), n.tabIndex = 0, n.setAttribute("role", "button"), n.setAttribute("aria-label", `Sort by ${e.header}`), n.addEventListener("click", () => this._requestSort(e.field)), n.addEventListener("keydown", (s) => {
2296
+ (s.key === "Enter" || s.key === " ") && (s.preventDefault(), this._requestSort(e.field));
2297
+ }));
2298
+ let i = document.createElement("span");
2299
+ if (i.className = "dt-table-header-label", i.textContent = e.header, this.sortable) {
2300
+ let s = document.createElement("span");
2301
+ s.className = "dt-table-sort-indicator", this._sortField === e.field ? s.textContent = this._sortDirection === "asc" ? "\u25B2" : "\u25BC" : s.textContent = "\u2195", i.appendChild(s);
2302
+ }
2303
+ n.appendChild(i), t.appendChild(n);
2304
+ }
2305
+ this._header.replaceChildren(t);
2306
+ }
2307
+ _renderBody() {
2308
+ if (this._rows.length === 0 || this._columns.length === 0) {
2309
+ this._emptyState.hidden = false, this._canvas.replaceChildren(), this._body.style.height = "140px", this._canvas.style.height = "0px";
2310
+ return;
2311
+ }
2312
+ this._emptyState.hidden = true, this._virtualizer.setCount(this._rows.length), this._virtualizer.setScrollTop(Math.max(0, this._scroll.scrollTop - this._header.offsetHeight)), this._virtualizer.setViewportHeight(Math.max(0, this._scroll.clientHeight - this._header.offsetHeight));
2313
+ let t = this._virtualizer.getRange();
2314
+ this._body.style.height = `${Math.max(t.totalHeight, this._scroll.clientHeight - this._header.offsetHeight)}px`, this._canvas.style.height = `${t.totalHeight}px`;
2315
+ let e = document.createDocumentFragment();
2316
+ for (let n = t.start; n < t.end; n += 1) e.appendChild(this._renderRow(n));
2317
+ this._canvas.replaceChildren(e);
2318
+ }
2319
+ _renderRow(t) {
2320
+ let e = this._rows[t], n = document.createElement("div");
2321
+ n.className = "dt-table-row dt-table-row--clickable", n.style.top = `${this._virtualizer.getOffset(t)}px`, n.style.height = `${this.rowHeight}px`, n.style.setProperty("--dt-table-columns", this._header.style.getPropertyValue("--dt-table-columns")), n.addEventListener("click", () => {
2322
+ this.dispatchEvent(new CustomEvent("dt-row-click", { detail: { row: e, index: t }, bubbles: true, composed: true }));
2323
+ });
2324
+ let i = Rt(e);
2325
+ for (let s of this._columns) {
2326
+ let o = document.createElement("div");
2327
+ if (o.className = "dt-table-cell", o.dataset.align = s.align, s.template) o.appendChild(M(s.template, i));
2328
+ else {
2329
+ let a = i[s.field];
2330
+ o.textContent = a == null ? "" : String(a);
2331
+ }
2332
+ n.appendChild(o);
2333
+ }
2334
+ return n;
2335
+ }
2336
+ _requestSort(t) {
2337
+ this._sortField === t ? this._sortDirection = this._sortDirection === "asc" ? "desc" : "asc" : (this._sortField = t, this._sortDirection = "asc"), this._renderHeader(), this.dispatchEvent(new CustomEvent("dt-sort", { detail: { field: t, direction: this._sortDirection }, bubbles: true, composed: true }));
2338
+ }
2339
+ _toGridColumn(t) {
2340
+ let e = /^\d+$/.test(t.minWidth) ? `${t.minWidth}px` : t.minWidth;
2341
+ if (t.width === "auto") return `minmax(${e}, 1fr)`;
2342
+ let n = /^\d+$/.test(t.width) ? `${t.width}px` : t.width;
2343
+ return `minmax(${e}, ${n})`;
2344
+ }
2345
+ };
2346
+ var it = `:host {
2347
+ display: block;
2348
+ min-height: 120px;
2349
+ color: var(--dt-text);
2350
+ font-family: var(
2351
+ --font-mono,
2352
+ 'SF Mono',
2353
+ Monaco,
2354
+ 'Cascadia Code',
2355
+ 'Roboto Mono',
2356
+ Consolas,
2357
+ monospace
2358
+ );
2359
+ }
2360
+
2361
+ .dt-list-view {
2362
+ position: relative;
2363
+ display: block;
2364
+ min-height: inherit;
2365
+ height: 100%;
2366
+ overflow: auto;
2367
+ background: var(--dt-surface);
2368
+ border: 1px solid var(--dt-border);
2369
+ border-radius: 2px;
2370
+ }
2371
+
2372
+ .dt-list-view::before,
2373
+ .dt-list-view::after {
2374
+ content: '';
2375
+ position: sticky;
2376
+ z-index: 2;
2377
+ width: 8px;
2378
+ height: 8px;
2379
+ pointer-events: none;
2380
+ }
2381
+
2382
+ .dt-list-view::before {
2383
+ top: 0;
2384
+ left: 0;
2385
+ display: block;
2386
+ border-top: 2px solid var(--dt-accent);
2387
+ border-left: 2px solid var(--dt-accent);
2388
+ }
2389
+
2390
+ .dt-list-view::after {
2391
+ right: 0;
2392
+ bottom: 0;
2393
+ float: right;
2394
+ border-right: 2px solid var(--dt-accent);
2395
+ border-bottom: 2px solid var(--dt-accent);
2396
+ }
2397
+
2398
+ .dt-list-spacer {
2399
+ position: relative;
2400
+ min-height: 100%;
2401
+ }
2402
+
2403
+ .dt-list-items {
2404
+ position: relative;
2405
+ }
2406
+
2407
+ .dt-list-item {
2408
+ box-sizing: border-box;
2409
+ width: 100%;
2410
+ padding: 12px;
2411
+ color: inherit;
2412
+ }
2413
+
2414
+ .dt-list-item--interactive {
2415
+ cursor: pointer;
2416
+ }
2417
+
2418
+ .dt-list-item--interactive:hover {
2419
+ background: var(--dt-surface-hover);
2420
+ }
2421
+
2422
+ .dt-list-item--selected {
2423
+ background: var(--dt-accent-subtle);
2424
+ }
2425
+
2426
+ :host([dividers]) .dt-list-item {
2427
+ border-bottom: 1px solid var(--dt-border-subtle);
2428
+ }
2429
+
2430
+ :host([dividers]) .dt-list-item:last-child {
2431
+ border-bottom: 0;
2432
+ }
2433
+
2434
+ .dt-list-empty {
2435
+ display: flex;
2436
+ align-items: center;
2437
+ justify-content: center;
2438
+ min-height: 120px;
2439
+ padding: 20px;
2440
+ color: var(--dt-text-muted);
2441
+ text-transform: uppercase;
2442
+ letter-spacing: 0.08em;
2443
+ font-size: 0.75rem;
2444
+ }
2445
+ `;
2446
+ var st = 56;
2447
+ function Pt(r) {
2448
+ return r && typeof r == "object" ? r : { value: r };
2449
+ }
2450
+ var z = class extends HTMLElement {
2451
+ _items = [];
2452
+ _selectedIndices = /* @__PURE__ */ new Set();
2453
+ _renderItem = null;
2454
+ _virtualizer = new m({ estimateSize: st, overscan: 5 });
2455
+ _viewport;
2456
+ _spacer;
2457
+ _itemsLayer;
2458
+ _emptyState;
2459
+ _resizeObserver = null;
2460
+ _itemResizeObserver = null;
2461
+ static get observedAttributes() {
2462
+ return ["item-height", "dividers", "selectable", "empty-text"];
2463
+ }
2464
+ get items() {
2465
+ return this._items;
2466
+ }
2467
+ set items(t) {
2468
+ this._items = Array.isArray(t) ? t : [], this._selectedIndices = new Set([...this._selectedIndices].filter((e) => e < this._items.length)), this._virtualizer.setCount(this._items.length), this._syncSizingMode(true), this._render();
2469
+ }
2470
+ get selectedItems() {
2471
+ return [...this._selectedIndices].sort((t, e) => t - e).map((t) => this._items[t]);
2472
+ }
2473
+ get renderItem() {
2474
+ return this._renderItem;
2475
+ }
2476
+ set renderItem(t) {
2477
+ this._renderItem = typeof t == "function" ? t : null, this._render();
2478
+ }
2479
+ get itemHeight() {
2480
+ let t = this.getAttribute("item-height");
2481
+ if (!t) return null;
2482
+ let e = Number(t);
2483
+ return Number.isFinite(e) && e > 0 ? e : null;
2484
+ }
2485
+ set itemHeight(t) {
2486
+ if (t === null || t <= 0) {
2487
+ this.removeAttribute("item-height");
2488
+ return;
2489
+ }
2490
+ this.setAttribute("item-height", String(t));
2491
+ }
2492
+ get selectable() {
2493
+ let t = this.getAttribute("selectable");
2494
+ return t === "single" || t === "multi" ? t : "none";
2495
+ }
2496
+ set selectable(t) {
2497
+ this.setAttribute("selectable", t);
2498
+ }
2499
+ get emptyText() {
2500
+ return this.getAttribute("empty-text") ?? "No items";
2501
+ }
2502
+ set emptyText(t) {
2503
+ this.setAttribute("empty-text", t);
2504
+ }
2505
+ constructor() {
2506
+ super();
2507
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
2508
+ e.textContent = it, t.appendChild(e), this._viewport = document.createElement("div"), this._viewport.className = "dt-list-view", this._viewport.addEventListener("scroll", this._onScroll, { passive: true }), this._spacer = document.createElement("div"), this._spacer.className = "dt-list-spacer", this._itemsLayer = document.createElement("div"), this._itemsLayer.className = "dt-list-items", this._emptyState = document.createElement("div"), this._emptyState.className = "dt-list-empty", this._spacer.append(this._itemsLayer, this._emptyState), this._viewport.appendChild(this._spacer), t.appendChild(this._viewport);
2509
+ }
2510
+ connectedCallback() {
2511
+ this._resizeObserver = new ResizeObserver((t) => {
2512
+ for (let e of t) e.target === this._viewport && (this._virtualizer.setViewportHeight(e.contentRect.height), this._render());
2513
+ }), this._resizeObserver.observe(this._viewport), this._itemResizeObserver = new ResizeObserver((t) => {
2514
+ let e = 0;
2515
+ for (let n of t) {
2516
+ let i = n.target, s = Number(i.dataset.index);
2517
+ Number.isFinite(s) && (e += this._virtualizer.measure(s, n.contentRect.height));
2518
+ }
2519
+ e !== 0 && (this._viewport.scrollTop += e), t.length > 0 && this._render();
2520
+ }), this._virtualizer.setCount(this._items.length), this._virtualizer.setViewportHeight(this._viewport.clientHeight), this._syncSizingMode(false), this._render();
2521
+ }
2522
+ disconnectedCallback() {
2523
+ this._viewport.removeEventListener("scroll", this._onScroll), this._resizeObserver?.disconnect(), this._itemResizeObserver?.disconnect(), this._resizeObserver = null, this._itemResizeObserver = null;
2524
+ }
2525
+ attributeChangedCallback(t) {
2526
+ t === "item-height" && this._syncSizingMode(true), t === "selectable" && this.selectable === "none" && this._selectedIndices.size > 0 && (this._selectedIndices.clear(), this._emitSelectionChange()), this._render();
2527
+ }
2528
+ _onScroll = () => {
2529
+ this._virtualizer.setScrollTop(this._viewport.scrollTop), this._render();
2530
+ };
2531
+ _syncSizingMode(t) {
2532
+ let e = this.itemHeight;
2533
+ this._virtualizer.setFixedSize(e), this._virtualizer.setEstimateSize(e ?? st), t && this._virtualizer.resetMeasurements();
2534
+ }
2535
+ _render() {
2536
+ if (!this.isConnected) return;
2537
+ if (this._emptyState.textContent = this.emptyText, this._emptyState.hidden = this._items.length > 0, this._items.length === 0) {
2538
+ this._itemsLayer.replaceChildren(), this._spacer.style.height = "100%";
2539
+ return;
2540
+ }
2541
+ this._virtualizer.setScrollTop(this._viewport.scrollTop), this._virtualizer.setViewportHeight(this._viewport.clientHeight), this._virtualizer.setCount(this._items.length);
2542
+ let t = this._virtualizer.getRange();
2543
+ this._spacer.style.height = `${Math.max(t.totalHeight, this._viewport.clientHeight)}px`, this._itemsLayer.style.transform = `translateY(${t.paddingTop}px)`;
2544
+ let e = document.createDocumentFragment();
2545
+ for (let n = t.start; n < t.end; n += 1) e.appendChild(this._renderVisibleItem(n));
2546
+ this._itemsLayer.replaceChildren(e);
2547
+ }
2548
+ _renderVisibleItem(t) {
2549
+ let e = this._items[t], n = document.createElement("div");
2550
+ if (n.className = "dt-list-item", n.dataset.index = String(t), this.selectable !== "none" && (n.classList.add("dt-list-item--interactive"), n.setAttribute("role", "option"), n.setAttribute("aria-selected", String(this._selectedIndices.has(t))), n.tabIndex = 0), this._selectedIndices.has(t) && n.classList.add("dt-list-item--selected"), this.itemHeight !== null && (n.style.minHeight = `${this.itemHeight}px`), this._renderItem) this._renderItem(e, n, t);
2551
+ else {
2552
+ let i = this._getTemplate();
2553
+ i ? n.appendChild(M(i, Pt(e))) : n.textContent = String(e ?? "");
2554
+ }
2555
+ return n.addEventListener("click", () => this._handleItemClick(t)), n.addEventListener("keydown", (i) => {
2556
+ (i.key === "Enter" || i.key === " ") && (i.preventDefault(), this._handleItemClick(t));
2557
+ }), this.itemHeight === null && this._itemResizeObserver?.observe(n), n;
2558
+ }
2559
+ _handleItemClick(t) {
2560
+ let e = this._items[t], n = this.selectable;
2561
+ n === "single" ? (this._selectedIndices = /* @__PURE__ */ new Set([t]), this._emitSelectionChange(), this._render()) : n === "multi" && (this._selectedIndices.has(t) ? this._selectedIndices.delete(t) : this._selectedIndices.add(t), this._emitSelectionChange(), this._render()), this.dispatchEvent(new CustomEvent("dt-item-click", { detail: { item: e, index: t }, bubbles: true, composed: true }));
2562
+ }
2563
+ _emitSelectionChange() {
2564
+ this.dispatchEvent(new CustomEvent("dt-selection-change", { detail: { selected: this.selectedItems }, bubbles: true, composed: true }));
2565
+ }
2566
+ _getTemplate() {
2567
+ for (let t of Array.from(this.children)) if (t instanceof HTMLTemplateElement) return t;
2568
+ return null;
2569
+ }
2570
+ };
2571
+ var ot = `:host {
2572
+ display: block;
2573
+ min-height: 220px;
2574
+ color: var(--dt-text);
2575
+ font-family: var(
2576
+ --font-mono,
2577
+ 'SF Mono',
2578
+ Monaco,
2579
+ 'Cascadia Code',
2580
+ 'Roboto Mono',
2581
+ Consolas,
2582
+ monospace
2583
+ );
2584
+ }
2585
+
2586
+ .dt-chart {
2587
+ position: relative;
2588
+ display: block;
2589
+ min-height: inherit;
2590
+ height: 100%;
2591
+ overflow: hidden;
2592
+ border: 1px solid var(--dt-border);
2593
+ border-radius: 2px;
2594
+ background:
2595
+ radial-gradient(
2596
+ circle at top left,
2597
+ color-mix(in srgb, var(--dt-accent) 16%, transparent),
2598
+ transparent 42%
2599
+ ),
2600
+ linear-gradient(
2601
+ 180deg,
2602
+ color-mix(in srgb, var(--dt-surface) 90%, var(--dt-accent) 10%),
2603
+ var(--dt-surface)
2604
+ );
2605
+ }
2606
+
2607
+ .dt-chart::before,
2608
+ .dt-chart::after {
2609
+ content: '';
2610
+ position: absolute;
2611
+ z-index: 3;
2612
+ width: 8px;
2613
+ height: 8px;
2614
+ pointer-events: none;
2615
+ }
2616
+
2617
+ .dt-chart::before {
2618
+ top: -1px;
2619
+ left: -1px;
2620
+ border-top: 2px solid var(--dt-accent);
2621
+ border-left: 2px solid var(--dt-accent);
2622
+ }
2623
+
2624
+ .dt-chart::after {
2625
+ right: -1px;
2626
+ bottom: -1px;
2627
+ border-right: 2px solid var(--dt-accent);
2628
+ border-bottom: 2px solid var(--dt-accent);
2629
+ }
2630
+
2631
+ .dt-chart__canvas {
2632
+ position: relative;
2633
+ z-index: 1;
2634
+ display: block;
2635
+ width: 100%;
2636
+ height: 100%;
2637
+ }
2638
+
2639
+ .dt-chart__status {
2640
+ position: absolute;
2641
+ inset: 0;
2642
+ z-index: 2;
2643
+ display: flex;
2644
+ align-items: center;
2645
+ justify-content: center;
2646
+ padding: 20px;
2647
+ color: var(--dt-text-muted);
2648
+ font-size: 0.75rem;
2649
+ letter-spacing: 0.08em;
2650
+ text-align: center;
2651
+ text-transform: uppercase;
2652
+ background: color-mix(in srgb, var(--dt-surface) 72%, transparent);
2653
+ }
2654
+
2655
+ .dt-chart__status[hidden] {
2656
+ display: none;
2657
+ }
2658
+ `;
2659
+ var L = null;
2660
+ function at() {
2661
+ return window.__DtChart ? Promise.resolve(window.__DtChart) : L || (L = new Promise((r, t) => {
2662
+ let e = document.createElement("script");
2663
+ e.src = "/api/ui/chart.umd.js", e.async = true, e.dataset.dtChart = "true", e.onload = () => {
2664
+ if (window.__DtChart) {
2665
+ r(window.__DtChart);
2666
+ return;
2667
+ }
2668
+ t(new Error("Chart runtime loaded without a __DtChart export."));
2669
+ }, e.onerror = () => t(new Error("Failed to load the Chart.js runtime bundle.")), document.head.appendChild(e);
2670
+ }), L);
2671
+ }
2672
+ function v(r, t, e) {
2673
+ return Math.min(e, Math.max(t, r));
2674
+ }
2675
+ function It(r) {
2676
+ return r ? r.split(",").map((t) => t.trim()).filter(Boolean) : [];
2677
+ }
2678
+ function X(r) {
2679
+ let t = r.trim().match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
2680
+ if (t) {
2681
+ let i = t[1], s = i.length === 3 ? i.split("").map((c) => `${c}${c}`).join("") : i, o = parseInt(s.slice(0, 2), 16) / 255, a = parseInt(s.slice(2, 4), 16) / 255, d = parseInt(s.slice(4, 6), 16) / 255;
2682
+ return dt(o, a, d);
2683
+ }
2684
+ let e = r.trim().match(/^rgba?\((\d+(?:\.\d+)?)[,\s]+(\d+(?:\.\d+)?)[,\s]+(\d+(?:\.\d+)?)(?:[,/\s]+[\d.]+)?\)$/i);
2685
+ if (e) return dt(Number(e[1]) / 255, Number(e[2]) / 255, Number(e[3]) / 255);
2686
+ let n = r.trim().match(/^hsla?\(([-\d.]+)(?:deg)?[,\s]+([\d.]+)%[,\s]+([\d.]+)%(?:[,/\s]+[\d.]+)?\)$/i);
2687
+ return n ? { h: (Number(n[1]) % 360 + 360) % 360, s: v(Number(n[2]), 0, 100), l: v(Number(n[3]), 0, 100) } : null;
2688
+ }
2689
+ function dt(r, t, e) {
2690
+ let n = Math.max(r, t, e), i = Math.min(r, t, e), s = n - i, o = 0, a = (n + i) / 2, d = s === 0 ? 0 : s / (1 - Math.abs(2 * a - 1));
2691
+ if (s !== 0) switch (n) {
2692
+ case r:
2693
+ o = 60 * ((t - e) / s % 6);
2694
+ break;
2695
+ case t:
2696
+ o = 60 * ((e - r) / s + 2);
2697
+ break;
2698
+ default:
2699
+ o = 60 * ((r - t) / s + 4);
2700
+ break;
2701
+ }
2702
+ return { h: (o + 360) % 360, s: Math.round(d * 100), l: Math.round(a * 100) };
2703
+ }
2704
+ function g(r, t = 1) {
2705
+ return `hsla(${Math.round(r.h)} ${Math.round(r.s)}% ${Math.round(r.l)}% / ${t})`;
2706
+ }
2707
+ function Nt(r) {
2708
+ let t = X(r) ?? { h: 185, s: 88, l: 56 };
2709
+ return [0, 32, 68, 118, 164, 212, 258, 304].map((n, i) => ({ h: (t.h + n) % 360, s: v(t.s - i * 2, 55, 90), l: v(t.l + (i % 2 === 0 ? 0 : 6) - i, 38, 66) }));
2710
+ }
2711
+ function H(r) {
2712
+ return !!r && typeof r == "object" && !Array.isArray(r);
2713
+ }
2714
+ function lt(r, t) {
2715
+ if (!H(r) || !H(t)) return t ?? r;
2716
+ let e = { ...r };
2717
+ for (let [n, i] of Object.entries(t)) {
2718
+ let s = e[n];
2719
+ e[n] = H(s) && H(i) ? lt(s, i) : i;
2720
+ }
2721
+ return e;
2722
+ }
2723
+ function Ft(r) {
2724
+ return r === "top" || r === "bottom" || r === "left" || r === "right" ? r : "none";
2725
+ }
2726
+ function Ot(r) {
2727
+ return r === "bar" || r === "line" || r === "area" || r === "pie" || r === "doughnut" || r === "radar" || r === "scatter" || r === "bubble" ? r : "bar";
2728
+ }
2729
+ function Bt(r) {
2730
+ return r === "bar" || r === "line" || r === "area" || r === "scatter" || r === "bubble";
2731
+ }
2732
+ function $t(r) {
2733
+ return r.map((t) => t.trim()).filter(Boolean);
2734
+ }
2735
+ var R = class extends HTMLElement {
2736
+ _canvas;
2737
+ _status;
2738
+ _runtime = null;
2739
+ _loadPromise = null;
2740
+ _chart = null;
2741
+ _renderedType = null;
2742
+ _dataInput = null;
2743
+ _optionsOverride = null;
2744
+ _syncFrame = 0;
2745
+ static get observedAttributes() {
2746
+ return ["type", "legend", "stacked", "labels"];
2747
+ }
2748
+ get type() {
2749
+ return Ot(this.getAttribute("type"));
2750
+ }
2751
+ set type(t) {
2752
+ this.setAttribute("type", t);
2753
+ }
2754
+ get legend() {
2755
+ return Ft(this.getAttribute("legend"));
2756
+ }
2757
+ set legend(t) {
2758
+ this.setAttribute("legend", t);
2759
+ }
2760
+ get stacked() {
2761
+ return this.hasAttribute("stacked");
2762
+ }
2763
+ set stacked(t) {
2764
+ this.toggleAttribute("stacked", t);
2765
+ }
2766
+ get labels() {
2767
+ return $t(It(this.getAttribute("labels")));
2768
+ }
2769
+ set labels(t) {
2770
+ this.setAttribute("labels", t.join(","));
2771
+ }
2772
+ get data() {
2773
+ return this._dataInput;
2774
+ }
2775
+ set data(t) {
2776
+ this._dataInput = t ? structuredClone(t) : null, this._scheduleSync();
2777
+ }
2778
+ get options() {
2779
+ return this._optionsOverride;
2780
+ }
2781
+ set options(t) {
2782
+ this._optionsOverride = t ? structuredClone(t) : null, this._renderChart();
2783
+ }
2784
+ constructor() {
2785
+ super();
2786
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
2787
+ e.textContent = ot, t.appendChild(e);
2788
+ let n = document.createElement("div");
2789
+ n.className = "dt-chart", this._canvas = document.createElement("canvas"), this._canvas.className = "dt-chart__canvas", this._status = document.createElement("div"), this._status.className = "dt-chart__status", this._status.textContent = "Loading chart", n.append(this._canvas, this._status), t.appendChild(n);
2790
+ }
2791
+ connectedCallback() {
2792
+ this._canvas.addEventListener("click", this._handleCanvasClick), this._ensureRuntime().then(() => this._renderChart()), this._scheduleSync();
2793
+ }
2794
+ disconnectedCallback() {
2795
+ this._canvas.removeEventListener("click", this._handleCanvasClick), this._syncFrame !== 0 && (cancelAnimationFrame(this._syncFrame), this._syncFrame = 0), this._chart?.destroy(), this._chart = null, this._renderedType = null;
2796
+ }
2797
+ attributeChangedCallback() {
2798
+ this._scheduleSync();
2799
+ }
2800
+ _handleCanvasClick = (t) => {
2801
+ if (!this._chart) return;
2802
+ let n = this._chart.getElementsAtEventForMode(t, "nearest", { intersect: true }, true)[0];
2803
+ if (!n) return;
2804
+ let i = Array.isArray(this._chart.data.labels) ? this._chart.data.labels[n.index] ?? null : null, s = this._chart.data.datasets[n.datasetIndex], o = Array.isArray(s?.data) ? s.data[n.index] : void 0;
2805
+ this.dispatchEvent(new CustomEvent("dt-chart-click", { bubbles: true, composed: true, detail: { label: i, datasetIndex: n.datasetIndex, index: n.index, value: o } }));
2806
+ };
2807
+ _scheduleSync() {
2808
+ this._syncFrame === 0 && (this._syncFrame = requestAnimationFrame(() => {
2809
+ this._syncFrame = 0, this._syncFromCurrentSource();
2810
+ }));
2811
+ }
2812
+ _syncFromCurrentSource() {
2813
+ this._renderChart();
2814
+ }
2815
+ async _ensureRuntime() {
2816
+ return this._runtime ? this._runtime : (this._loadPromise || (this._loadPromise = at().then((t) => (this._runtime = t, t))), this._loadPromise);
2817
+ }
2818
+ async _renderChart() {
2819
+ let t = this._dataInput;
2820
+ if (!t) {
2821
+ this._setStatus("Waiting for data");
2822
+ return;
2823
+ }
2824
+ let e = await this._ensureRuntime(), n = this._buildConfig(e, t), i = n.type;
2825
+ !this._chart || this._renderedType !== i ? (this._chart?.destroy(), this._chart = new e.Chart(this._canvas, n), this._renderedType = i) : (this._chart.data = n.data, this._chart.options = n.options, this._chart.update()), this._setStatus(t.datasets.length > 0 ? null : "Waiting for data");
2826
+ }
2827
+ _buildConfig(t, e) {
2828
+ let n = getComputedStyle(this), i = n.getPropertyValue("--dt-accent").trim() || "#42d4ff", s = n.getPropertyValue("--dt-text").trim() || "#d6ebff", o = n.getPropertyValue("--dt-text-muted").trim() || "#7b93a6", a = n.getPropertyValue("--dt-border").trim() || "rgba(123, 147, 166, 0.3)", d = n.getPropertyValue("--font-mono").trim() || "'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace", c = Nt(i), l = this.type === "area" ? "line" : this.type, f = { labels: e.labels ?? this.labels, datasets: e.datasets.map((h, gt) => {
2829
+ let F = c[gt % c.length], p = h.color ?? g(F, 1), O = { label: h.label ?? "", data: h.data, backgroundColor: l === "line" || l === "radar" || l === "scatter" ? g(F, l === "scatter" ? 0.95 : 0.24) : p, borderColor: p, pointBackgroundColor: p, pointBorderColor: p, pointHoverBackgroundColor: p, pointRadius: this.type === "line" || this.type === "area" ? 3 : 4, pointHoverRadius: this.type === "line" || this.type === "area" ? 5 : 6, borderWidth: 2, tension: l === "line" || this.type === "area" ? 0.32 : void 0, fill: this.type === "area" };
2830
+ return l === "pie" || l === "doughnut" ? { ...O, backgroundColor: Array.isArray(h.data) ? h.data.map((bt, B) => g(c[B % c.length], 0.86)) : p, borderColor: Array.isArray(h.data) ? h.data.map((bt, B) => g(c[B % c.length], 1)) : p, borderWidth: 1 } : l === "scatter" || l === "bubble" ? { ...O, showLine: false, backgroundColor: g(F, 0.78) } : O;
2831
+ }) }, _ = { responsive: true, maintainAspectRatio: false, animation: { duration: 320 }, interaction: { mode: "nearest", intersect: true }, plugins: { legend: { display: this.legend !== "none", position: this.legend === "none" ? "top" : this.legend, labels: { color: s, boxWidth: 12, boxHeight: 12, padding: 14, font: { family: d, size: 11 } } }, tooltip: { backgroundColor: "rgba(10, 18, 24, 0.92)", borderColor: Xt(a, i, 0.35), borderWidth: 1, titleColor: s, bodyColor: s, footerColor: o, titleFont: { family: d, size: 11 }, bodyFont: { family: d, size: 11 }, padding: 10 } }, scales: Bt(this.type) ? { x: { stacked: this.stacked, grid: { display: false, color: a }, border: { color: a }, ticks: { color: o, font: { family: d, size: 11 } } }, y: { stacked: this.stacked, beginAtZero: true, grid: { display: false, color: a }, border: { color: a }, ticks: { color: o, font: { family: d, size: 11 } } } } : l === "radar" ? { r: { angleLines: { color: a }, grid: { color: a }, pointLabels: { color: o, font: { family: d, size: 11 } }, ticks: { color: o, backdropColor: "transparent", font: { family: d, size: 10 } } } } : void 0 };
2832
+ return { type: l, data: f, options: lt(_, this._optionsOverride ?? {}) };
2833
+ }
2834
+ _setStatus(t) {
2835
+ if (!t) {
2836
+ this._status.hidden = true;
2837
+ return;
2838
+ }
2839
+ this._status.hidden = false, this._status.textContent = t;
2840
+ }
2841
+ };
2842
+ function Xt(r, t, e) {
2843
+ let n = X(r), i = X(t);
2844
+ if (!n || !i) return r;
2845
+ let s = v(e, 0, 1), o = ((i.h - n.h) % 360 + 540) % 360 - 180;
2846
+ return g({ h: (n.h + o * s + 360) % 360, s: n.s + (i.s - n.s) * s, l: n.l + (i.l - n.l) * s });
2847
+ }
2848
+ var ct = `:host {
2849
+ display: block;
2850
+ color: var(--dt-text);
2851
+ font-family: var(--font-sans, 'Inter', sans-serif);
2852
+ }
2853
+
2854
+ .dt-markdown {
2855
+ color: inherit;
2856
+ line-height: 1.7;
2857
+ word-break: break-word;
2858
+ }
2859
+
2860
+ .dt-markdown > :first-child {
2861
+ margin-top: 0;
2862
+ }
2863
+
2864
+ .dt-markdown > :last-child {
2865
+ margin-bottom: 0;
2866
+ }
2867
+
2868
+ .dt-markdown :is(h1, h2, h3, h4, h5, h6) {
2869
+ margin: 1.2em 0 0.55em;
2870
+ color: var(--dt-text);
2871
+ font-family: var(--font-sans, 'Inter', sans-serif);
2872
+ line-height: 1.2;
2873
+ }
2874
+
2875
+ .dt-markdown h1 {
2876
+ color: var(--dt-accent);
2877
+ font-size: 1.6rem;
2878
+ letter-spacing: 0.08em;
2879
+ text-transform: uppercase;
2880
+ }
2881
+
2882
+ .dt-markdown h2 {
2883
+ font-size: 1.3rem;
2884
+ }
2885
+
2886
+ .dt-markdown h3 {
2887
+ font-size: 1.1rem;
2888
+ }
2889
+
2890
+ .dt-markdown p,
2891
+ .dt-markdown ul,
2892
+ .dt-markdown ol,
2893
+ .dt-markdown blockquote,
2894
+ .dt-markdown pre,
2895
+ .dt-markdown table {
2896
+ margin: 0.8em 0;
2897
+ }
2898
+
2899
+ .dt-markdown ul,
2900
+ .dt-markdown ol {
2901
+ padding-left: 1.4rem;
2902
+ }
2903
+
2904
+ .dt-markdown li + li {
2905
+ margin-top: 0.28em;
2906
+ }
2907
+
2908
+ .dt-markdown strong {
2909
+ color: var(--dt-text);
2910
+ }
2911
+
2912
+ .dt-markdown a,
2913
+ .dt-markdown .dt-md-link {
2914
+ color: var(--dt-accent);
2915
+ text-decoration: none;
2916
+ }
2917
+
2918
+ .dt-markdown a:hover,
2919
+ .dt-markdown .dt-md-link:hover {
2920
+ text-decoration: underline;
2921
+ }
2922
+
2923
+ .dt-markdown code {
2924
+ padding: 0.12rem 0.35rem;
2925
+ border-radius: 2px;
2926
+ background: color-mix(in srgb, var(--dt-surface) 88%, var(--dt-accent) 12%);
2927
+ color: var(--dt-accent);
2928
+ font-family: var(
2929
+ --font-mono,
2930
+ 'SF Mono',
2931
+ Monaco,
2932
+ 'Cascadia Code',
2933
+ 'Roboto Mono',
2934
+ Consolas,
2935
+ monospace
2936
+ );
2937
+ font-size: 0.92em;
2938
+ }
2939
+
2940
+ .dt-md-pre {
2941
+ overflow-x: auto;
2942
+ padding: 14px 16px;
2943
+ border: 1px solid var(--dt-border);
2944
+ border-radius: 2px;
2945
+ background: var(--dt-surface);
2946
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dt-surface) 85%, var(--dt-accent) 15%);
2947
+ }
2948
+
2949
+ .dt-md-pre code {
2950
+ display: block;
2951
+ padding: 0;
2952
+ background: transparent;
2953
+ color: var(--dt-text);
2954
+ }
2955
+
2956
+ .dt-md-blockquote {
2957
+ margin: 0.9em 0;
2958
+ padding: 0.15rem 0 0.15rem 1rem;
2959
+ border-left: 3px solid var(--dt-accent);
2960
+ color: var(--dt-text-muted);
2961
+ }
2962
+
2963
+ .dt-md-table {
2964
+ width: 100%;
2965
+ border-collapse: collapse;
2966
+ border: 1px solid var(--dt-border);
2967
+ background: var(--dt-surface);
2968
+ }
2969
+
2970
+ .dt-md-table th,
2971
+ .dt-md-table td {
2972
+ padding: 0.6rem 0.8rem;
2973
+ border: 1px solid var(--dt-border-subtle, var(--dt-border));
2974
+ text-align: left;
2975
+ vertical-align: top;
2976
+ }
2977
+
2978
+ .dt-md-table th {
2979
+ color: var(--dt-accent);
2980
+ background: color-mix(in srgb, var(--dt-surface) 88%, var(--dt-accent) 12%);
2981
+ font-size: 0.75rem;
2982
+ letter-spacing: 0.08em;
2983
+ text-transform: uppercase;
2984
+ }
2985
+
2986
+ .dt-markdown hr {
2987
+ border: 0;
2988
+ border-top: 1px solid var(--dt-border);
2989
+ }
2990
+
2991
+ .dt-md-image {
2992
+ display: block;
2993
+ max-width: 100%;
2994
+ border: 1px solid var(--dt-border);
2995
+ border-radius: 2px;
2996
+ }
2997
+
2998
+ .dt-markdown__caret {
2999
+ display: inline-block;
3000
+ margin-left: 0.15rem;
3001
+ color: var(--dt-accent);
3002
+ animation: dt-markdown-caret 0.9s steps(1) infinite;
3003
+ }
3004
+
3005
+ .dt-markdown__caret[hidden] {
3006
+ display: none;
3007
+ }
3008
+
3009
+ @keyframes dt-markdown-caret {
3010
+ 0%,
3011
+ 49% {
3012
+ opacity: 1;
3013
+ }
3014
+
3015
+ 50%,
3016
+ 100% {
3017
+ opacity: 0;
3018
+ }
3019
+ }
3020
+ `;
3021
+ var V = null;
3022
+ function ht() {
3023
+ return window.__DtMarked ? Promise.resolve(window.__DtMarked) : V || (V = new Promise((r, t) => {
3024
+ let e = document.createElement("script");
3025
+ e.src = "/api/ui/marked.js", e.async = true, e.dataset.dtMarked = "true", e.onload = () => {
3026
+ if (window.__DtMarked) {
3027
+ r(window.__DtMarked);
3028
+ return;
3029
+ }
3030
+ t(new Error("Marked runtime loaded without a __DtMarked export."));
3031
+ }, e.onerror = () => t(new Error("Failed to load the marked runtime bundle.")), document.head.appendChild(e);
3032
+ }), V);
3033
+ }
3034
+ function ut(r) {
3035
+ return r.replaceAll(`\r
3036
+ `, `
3037
+ `);
3038
+ }
3039
+ function Jt(r) {
3040
+ let t = ut(r).split(`
3041
+ `);
3042
+ for (; t.length > 0 && t[0].trim() === ""; ) t.shift();
3043
+ for (; t.length > 0 && t[t.length - 1].trim() === ""; ) t.pop();
3044
+ let e = t.filter((i) => i.trim() !== "").map((i) => i.match(/^\s*/)?.[0].length ?? 0), n = e.length > 0 ? Math.min(...e) : 0;
3045
+ return n === 0 ? t.join(`
3046
+ `) : t.map((i) => i.slice(n)).join(`
3047
+ `);
3048
+ }
3049
+ function Wt(r) {
3050
+ let t = ut(r);
3051
+ if ((t.match(/(^|\n)(```|~~~)/g) ?? []).length % 2 === 0) return t;
3052
+ let n = t.includes("~~~") && !t.includes("```") ? "~~~" : "```";
3053
+ return `${t}
3054
+ ${n}`;
3055
+ }
3056
+ var P = class extends HTMLElement {
3057
+ _body;
3058
+ _caret;
3059
+ _contentOverride = null;
3060
+ _runtime = null;
3061
+ _loadPromise = null;
3062
+ _observer = null;
3063
+ _renderFrame = 0;
3064
+ static get observedAttributes() {
3065
+ return ["streaming", "unsafe-html"];
3066
+ }
3067
+ get content() {
3068
+ return this._contentOverride ?? this._readInlineMarkdown();
3069
+ }
3070
+ set content(t) {
3071
+ this._contentOverride = String(t ?? ""), this._scheduleRender();
3072
+ }
3073
+ get streaming() {
3074
+ return this.hasAttribute("streaming");
3075
+ }
3076
+ set streaming(t) {
3077
+ this.toggleAttribute("streaming", t);
3078
+ }
3079
+ get unsafeHtml() {
3080
+ return this.hasAttribute("unsafe-html");
3081
+ }
3082
+ set unsafeHtml(t) {
3083
+ this.toggleAttribute("unsafe-html", t);
3084
+ }
3085
+ constructor() {
3086
+ super();
3087
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
3088
+ e.textContent = ct, t.appendChild(e), this._body = document.createElement("div"), this._body.className = "dt-markdown", this._body.addEventListener("click", this._onLinkClick), this._caret = document.createElement("span"), this._caret.className = "dt-markdown__caret", this._caret.textContent = "\u258C", this._caret.hidden = true, t.append(this._body, this._caret);
3089
+ }
3090
+ connectedCallback() {
3091
+ this._observer || (this._observer = new MutationObserver(() => {
3092
+ this._contentOverride === null && this._scheduleRender();
3093
+ }), this._observer.observe(this, { childList: true, characterData: true, subtree: true })), this._ensureRuntime(), this._scheduleRender();
3094
+ }
3095
+ disconnectedCallback() {
3096
+ this._observer?.disconnect(), this._observer = null, this._renderFrame !== 0 && (cancelAnimationFrame(this._renderFrame), this._renderFrame = 0);
3097
+ }
3098
+ attributeChangedCallback() {
3099
+ this._scheduleRender();
3100
+ }
3101
+ _onLinkClick = (t) => {
3102
+ let n = t.composedPath().find((i) => i instanceof HTMLAnchorElement);
3103
+ n && (t.preventDefault(), this.dispatchEvent(new CustomEvent("dt-link-click", { bubbles: true, composed: true, detail: { href: n.getAttribute("href") ?? "#" } })));
3104
+ };
3105
+ _readInlineMarkdown() {
3106
+ return Jt(this.textContent ?? "");
3107
+ }
3108
+ _scheduleRender() {
3109
+ this._renderFrame === 0 && (this._renderFrame = requestAnimationFrame(() => {
3110
+ this._renderFrame = 0, this._render();
3111
+ }));
3112
+ }
3113
+ async _ensureRuntime() {
3114
+ return this._runtime ? this._runtime : (this._loadPromise || (this._loadPromise = ht().then((t) => (this._runtime = t, t))), this._loadPromise);
3115
+ }
3116
+ async _render() {
3117
+ let t = await this._ensureRuntime(), e = this.content;
3118
+ this.streaming && (e = Wt(e)), this._body.innerHTML = t.render(e, { unsafeHtml: this.unsafeHtml }), this._caret.hidden = !this.streaming;
3119
+ }
3120
+ };
3121
+ var pt = `:host {
3122
+ display: block;
3123
+ min-height: 240px;
3124
+ color: var(--dt-text);
3125
+ font-family: var(--font-sans, 'Inter', sans-serif);
3126
+ }
3127
+
3128
+ .dt-markdown-editor {
3129
+ position: relative;
3130
+ height: 100%;
3131
+ min-height: inherit;
3132
+ overflow: hidden;
3133
+ border: 1px solid var(--dt-border);
3134
+ border-radius: 2px;
3135
+ }
3136
+
3137
+ .dt-markdown-editor::before,
3138
+ .dt-markdown-editor::after {
3139
+ content: '';
3140
+ position: absolute;
3141
+ z-index: 3;
3142
+ width: 8px;
3143
+ height: 8px;
3144
+ pointer-events: none;
3145
+ }
3146
+
3147
+ .dt-markdown-editor::before {
3148
+ top: -1px;
3149
+ left: -1px;
3150
+ border-top: 2px solid var(--dt-accent);
3151
+ border-left: 2px solid var(--dt-accent);
3152
+ }
3153
+
3154
+ .dt-markdown-editor::after {
3155
+ right: -1px;
3156
+ bottom: -1px;
3157
+ border-right: 2px solid var(--dt-accent);
3158
+ border-bottom: 2px solid var(--dt-accent);
3159
+ }
3160
+
3161
+ .dt-markdown-editor__surface {
3162
+ height: 100%;
3163
+ min-height: inherit;
3164
+ }
3165
+
3166
+ .dt-markdown-editor__content {
3167
+ height: 100%;
3168
+ min-height: inherit;
3169
+ }
3170
+
3171
+ .dt-markdown-editor__status {
3172
+ position: absolute;
3173
+ inset: 0;
3174
+ display: flex;
3175
+ align-items: center;
3176
+ justify-content: center;
3177
+ padding: 20px;
3178
+ background: color-mix(in srgb, var(--dt-surface) 84%, transparent);
3179
+ color: var(--dt-text-muted);
3180
+ font-size: 0.75rem;
3181
+ letter-spacing: 0.08em;
3182
+ text-transform: uppercase;
3183
+ }
3184
+
3185
+ .dt-markdown-editor__status[hidden] {
3186
+ display: none;
3187
+ }
3188
+
3189
+ .milkdown {
3190
+ --crepe-color-background: transparent;
3191
+ --crepe-color-on-background: var(--dt-text);
3192
+ --crepe-color-surface: var(--dt-surface);
3193
+ --crepe-color-surface-low: color-mix(in srgb, var(--dt-surface) 94%, var(--dt-accent) 6%);
3194
+ --crepe-color-on-surface: var(--dt-text);
3195
+ --crepe-color-on-surface-variant: var(--dt-text-muted);
3196
+ --crepe-color-outline: var(--dt-border);
3197
+ --crepe-color-primary: var(--dt-accent);
3198
+ --crepe-color-secondary: color-mix(in srgb, var(--dt-surface) 84%, var(--dt-accent) 16%);
3199
+ --crepe-color-on-secondary: var(--dt-text);
3200
+ --crepe-color-inverse: var(--dt-text);
3201
+ --crepe-color-on-inverse: var(--dt-surface);
3202
+ --crepe-color-inline-code: var(--dt-accent);
3203
+ --crepe-color-error: var(--dt-danger, #ff6a6a);
3204
+ --crepe-color-hover: var(--dt-surface-hover);
3205
+ --crepe-color-selected: color-mix(in srgb, var(--dt-surface) 82%, var(--dt-accent) 18%);
3206
+ --crepe-color-inline-area: color-mix(in srgb, var(--dt-surface) 90%, var(--dt-accent) 10%);
3207
+ --crepe-font-title: var(--font-sans, 'Inter', sans-serif);
3208
+ --crepe-font-default: var(--font-sans, 'Inter', sans-serif);
3209
+ --crepe-font-code: var(
3210
+ --font-mono,
3211
+ 'SF Mono',
3212
+ Monaco,
3213
+ 'Cascadia Code',
3214
+ 'Roboto Mono',
3215
+ Consolas,
3216
+ monospace
3217
+ );
3218
+ --crepe-shadow-1: 0 0 0 1px color-mix(in srgb, var(--dt-surface) 82%, var(--dt-accent) 18%);
3219
+ --crepe-shadow-2:
3220
+ 0 0 0 1px color-mix(in srgb, var(--dt-surface) 78%, var(--dt-accent) 22%),
3221
+ 0 8px 24px color-mix(in srgb, var(--dt-accent) 12%, transparent);
3222
+
3223
+ height: 100%;
3224
+ background: transparent;
3225
+ color: var(--dt-text);
3226
+ }
3227
+
3228
+ .milkdown .editor {
3229
+ min-height: 100%;
3230
+ padding: 16px 18px 20px;
3231
+ outline: none;
3232
+ color: var(--dt-text);
3233
+ font-family: var(--font-sans, 'Inter', sans-serif);
3234
+ font-size: 14px;
3235
+ line-height: 1.7;
3236
+ }
3237
+
3238
+ .milkdown .editor > :first-child {
3239
+ margin-top: 0;
3240
+ }
3241
+
3242
+ .milkdown .editor h1,
3243
+ .milkdown .editor h2,
3244
+ .milkdown .editor h3,
3245
+ .milkdown .editor h4,
3246
+ .milkdown .editor h5,
3247
+ .milkdown .editor h6 {
3248
+ margin: 0.95em 0 0.45em;
3249
+ line-height: 1.2;
3250
+ }
3251
+
3252
+ .milkdown .editor h1 {
3253
+ color: var(--dt-accent);
3254
+ font-size: 1.6rem;
3255
+ letter-spacing: 0.08em;
3256
+ text-transform: uppercase;
3257
+ }
3258
+
3259
+ .milkdown .editor h2 {
3260
+ font-size: 1.28rem;
3261
+ }
3262
+
3263
+ .milkdown .editor h3 {
3264
+ font-size: 1.08rem;
3265
+ }
3266
+
3267
+ .milkdown .editor p {
3268
+ margin: 0.65em 0;
3269
+ }
3270
+
3271
+ .milkdown .editor code {
3272
+ padding: 2px 5px;
3273
+ border-radius: 2px;
3274
+ background: color-mix(in srgb, var(--dt-surface) 88%, var(--dt-accent) 12%);
3275
+ font-family: var(
3276
+ --font-mono,
3277
+ 'SF Mono',
3278
+ Monaco,
3279
+ 'Cascadia Code',
3280
+ 'Roboto Mono',
3281
+ Consolas,
3282
+ monospace
3283
+ );
3284
+ font-size: 0.9em;
3285
+ }
3286
+
3287
+ .milkdown .editor pre {
3288
+ overflow-x: auto;
3289
+ margin: 0.9em 0;
3290
+ padding: 12px 14px;
3291
+ border: 1px solid var(--dt-border);
3292
+ border-radius: 2px;
3293
+ background: var(--dt-surface);
3294
+ }
3295
+
3296
+ .milkdown .editor pre code {
3297
+ padding: 0;
3298
+ background: transparent;
3299
+ }
3300
+
3301
+ .milkdown .editor blockquote {
3302
+ margin: 0.9em 0;
3303
+ padding-left: 12px;
3304
+ border-left: 3px solid var(--dt-accent);
3305
+ color: var(--dt-text-muted);
3306
+ }
3307
+
3308
+ .milkdown .editor a {
3309
+ color: var(--dt-accent);
3310
+ text-decoration: none;
3311
+ }
3312
+
3313
+ .milkdown .editor a:hover {
3314
+ text-decoration: underline;
3315
+ }
3316
+
3317
+ .milkdown .editor hr {
3318
+ border: 0;
3319
+ border-top: 1px solid var(--dt-border);
3320
+ }
3321
+
3322
+ .milkdown .editor ul,
3323
+ .milkdown .editor ol {
3324
+ padding-left: 1.5rem;
3325
+ }
3326
+
3327
+ .milkdown .editor img {
3328
+ max-width: 100%;
3329
+ border-radius: 2px;
3330
+ }
3331
+
3332
+ .milkdown .editor table {
3333
+ width: 100%;
3334
+ border-collapse: collapse;
3335
+ }
3336
+
3337
+ .milkdown .editor th,
3338
+ .milkdown .editor td {
3339
+ border: 1px solid var(--dt-border);
3340
+ }
3341
+ `;
3342
+ var I = null;
3343
+ function mt() {
3344
+ return window.__DtMilkdown ? Promise.resolve(window.__DtMilkdown) : I || (I = new Promise((r, t) => {
3345
+ let e = document.createElement("script");
3346
+ e.src = "/api/ui/milkdown.umd.js", e.async = true, e.dataset.dtMilkdown = "true", e.onload = () => {
3347
+ if (window.__DtMilkdown) {
3348
+ r(window.__DtMilkdown);
3349
+ return;
3350
+ }
3351
+ t(new Error("Milkdown runtime loaded without a __DtMilkdown export."));
3352
+ }, e.onerror = () => t(new Error("Failed to load the Milkdown runtime bundle.")), document.head.appendChild(e);
3353
+ }), I);
3354
+ }
3355
+ var N = class extends HTMLElement {
3356
+ _runtimeStyle;
3357
+ _surface;
3358
+ _content;
3359
+ _status;
3360
+ _runtime = null;
3361
+ _loadPromise = null;
3362
+ _editor = null;
3363
+ _pendingValue = "";
3364
+ _changeTimer = null;
3365
+ _setupToken = 0;
3366
+ _suppressNextChange = false;
3367
+ static get observedAttributes() {
3368
+ return ["placeholder", "readonly"];
3369
+ }
3370
+ get placeholder() {
3371
+ return this.getAttribute("placeholder") ?? "";
3372
+ }
3373
+ set placeholder(t) {
3374
+ this.setAttribute("placeholder", t);
3375
+ }
3376
+ get readonly() {
3377
+ return this.hasAttribute("readonly");
3378
+ }
3379
+ set readonly(t) {
3380
+ this.toggleAttribute("readonly", t);
3381
+ }
3382
+ get value() {
3383
+ return this._editor && (this._pendingValue = this._editor.getMarkdown()), this._pendingValue;
3384
+ }
3385
+ set value(t) {
3386
+ let e = String(t ?? "");
3387
+ this._pendingValue = e, this._editor && this._runtime && this._editor.getMarkdown() !== e && (this._suppressNextChange = true, this._editor.editor.action(this._runtime.replaceAll(e)));
3388
+ }
3389
+ constructor() {
3390
+ super();
3391
+ let t = this.attachShadow({ mode: "open" }), e = document.createElement("style");
3392
+ e.textContent = pt, t.appendChild(e), this._runtimeStyle = document.createElement("style"), t.appendChild(this._runtimeStyle), this._surface = document.createElement("div"), this._surface.className = "dt-markdown-editor", this._content = document.createElement("div"), this._content.className = "dt-markdown-editor__surface";
3393
+ let n = document.createElement("div");
3394
+ n.className = "dt-markdown-editor__content", this._content.appendChild(n), this._status = document.createElement("div"), this._status.className = "dt-markdown-editor__status", this._status.textContent = "Loading editor", this._surface.append(this._content, this._status), t.appendChild(this._surface);
3395
+ }
3396
+ connectedCallback() {
3397
+ this._initializeEditor();
3398
+ }
3399
+ disconnectedCallback() {
3400
+ this._setupToken += 1, this._clearChangeTimer(), this._destroyEditor();
3401
+ }
3402
+ attributeChangedCallback(t) {
3403
+ if (t === "readonly") {
3404
+ this._editor?.setReadonly(this.readonly);
3405
+ return;
3406
+ }
3407
+ t === "placeholder" && this.isConnected && this._initializeEditor(true);
3408
+ }
3409
+ async _ensureRuntime() {
3410
+ return this._runtime ? this._runtime : (this._loadPromise || (this._loadPromise = mt().then((t) => (this._runtime = t, this._runtimeStyle.textContent = t.cssText, t))), this._loadPromise);
3411
+ }
3412
+ async _initializeEditor(t = false) {
3413
+ let e = ++this._setupToken;
3414
+ if (this._setStatus("Loading editor"), t) await this._destroyEditor();
3415
+ else if (this._editor) {
3416
+ this._setStatus(null);
3417
+ return;
3418
+ }
3419
+ try {
3420
+ let n = await this._ensureRuntime();
3421
+ if (!this.isConnected || e !== this._setupToken) return;
3422
+ this._content.replaceChildren();
3423
+ let i = document.createElement("div");
3424
+ i.className = "dt-markdown-editor__content", this._content.appendChild(i);
3425
+ let s = new n.Crepe({ root: i, defaultValue: this._pendingValue, features: { [n.Crepe.Feature.CodeMirror]: false, [n.Crepe.Feature.ImageBlock]: false, [n.Crepe.Feature.Latex]: false }, featureConfigs: { [n.Crepe.Feature.Placeholder]: { text: this.placeholder, mode: "doc" } } });
3426
+ if (s.on((o) => {
3427
+ o.markdownUpdated((a, d) => {
3428
+ if (this._pendingValue = d, this._suppressNextChange) {
3429
+ this._suppressNextChange = false;
3430
+ return;
3431
+ }
3432
+ this._queueChange(d);
3433
+ }), o.focus(() => {
3434
+ this.dispatchEvent(new CustomEvent("dt-focus", { bubbles: true, composed: true }));
3435
+ }), o.blur(() => {
3436
+ this.dispatchEvent(new CustomEvent("dt-blur", { bubbles: true, composed: true }));
3437
+ });
3438
+ }), await s.create(), !this.isConnected || e !== this._setupToken) {
3439
+ await s.destroy();
3440
+ return;
3441
+ }
3442
+ this._editor = s, this._editor.setReadonly(this.readonly), this._pendingValue = this._editor.getMarkdown(), this._setStatus(null);
3443
+ } catch {
3444
+ e === this._setupToken && this._setStatus("Failed to load editor");
3445
+ }
3446
+ }
3447
+ async _destroyEditor() {
3448
+ let t = this._editor;
3449
+ if (this._editor = null, !!t) try {
3450
+ await t.destroy();
3451
+ } catch {
3452
+ }
3453
+ }
3454
+ _queueChange(t) {
3455
+ this._clearChangeTimer(), this._changeTimer = setTimeout(() => {
3456
+ this._changeTimer = null, this.dispatchEvent(new CustomEvent("dt-change", { bubbles: true, composed: true, detail: { value: t } }));
3457
+ }, 300);
3458
+ }
3459
+ _clearChangeTimer() {
3460
+ this._changeTimer && (clearTimeout(this._changeTimer), this._changeTimer = null);
3461
+ }
3462
+ _setStatus(t) {
3463
+ if (t) {
3464
+ this._status.hidden = false, this._status.textContent = t;
3465
+ return;
3466
+ }
3467
+ this._status.hidden = true;
3468
+ }
3469
+ };
3470
+ customElements.get("dt-tooltip") || customElements.define("dt-tooltip", x);
3471
+ customElements.get("dt-card") || customElements.define("dt-card", w);
3472
+ customElements.get("dt-select") || customElements.define("dt-select", y);
3473
+ customElements.get("dt-grid") || customElements.define("dt-grid", k);
3474
+ customElements.get("dt-stack") || customElements.define("dt-stack", C);
3475
+ customElements.get("dt-stat") || customElements.define("dt-stat", E);
3476
+ customElements.get("dt-badge") || customElements.define("dt-badge", S);
3477
+ customElements.get("dt-button") || customElements.define("dt-button", D);
3478
+ customElements.get("dt-divider") || customElements.define("dt-divider", A);
3479
+ customElements.get("dt-list-view") || customElements.define("dt-list-view", z);
3480
+ customElements.get("dt-table-view") || customElements.define("dt-table-view", T);
3481
+ customElements.get("dt-column") || customElements.define("dt-column", b);
3482
+ customElements.get("dt-chart") || customElements.define("dt-chart", R);
3483
+ customElements.get("dt-markdown") || customElements.define("dt-markdown", P);
3484
+ customElements.get("dt-markdown-editor") || customElements.define("dt-markdown-editor", N);
3485
+
3486
+ // src/styles/PreferenceApp.module.css
3487
+ var PreferenceApp_default = {
3488
+ root: "PreferenceApp_root",
3489
+ rootCompact: "PreferenceApp_rootCompact",
3490
+ sidebar: "PreferenceApp_sidebar",
3491
+ sidebarHeader: "PreferenceApp_sidebarHeader",
3492
+ categoryItem: "PreferenceApp_categoryItem",
3493
+ categoryItemActive: "PreferenceApp_categoryItem PreferenceApp_categoryItemActive",
3494
+ categoryIcon: "PreferenceApp_categoryIcon",
3495
+ categoryText: "PreferenceApp_categoryText",
3496
+ settingsPanel: "PreferenceApp_settingsPanel",
3497
+ section: "PreferenceApp_section",
3498
+ sectionTitle: "PreferenceApp_sectionTitle",
3499
+ row: "PreferenceApp_row",
3500
+ rowInfo: "PreferenceApp_rowInfo",
3501
+ rowLabel: "PreferenceApp_rowLabel",
3502
+ rowDescription: "PreferenceApp_rowDescription",
3503
+ rowRestartBadge: "PreferenceApp_rowRestartBadge",
3504
+ rowControl: "PreferenceApp_rowControl",
3505
+ providerGroup: "PreferenceApp_providerGroup",
3506
+ providerGroupHeader: "PreferenceApp_providerGroupHeader",
3507
+ providerList: "PreferenceApp_providerList",
3508
+ providerCard: "PreferenceApp_providerCard",
3509
+ providerCardBody: "PreferenceApp_providerCardBody",
3510
+ providerCardHeader: "PreferenceApp_providerCardHeader",
3511
+ providerCardTitleRow: "PreferenceApp_providerCardTitleRow",
3512
+ providerCardTitle: "PreferenceApp_providerCardTitle",
3513
+ providerDefaultBadge: "PreferenceApp_providerDefaultBadge",
3514
+ providerCardActions: "PreferenceApp_providerCardActions",
3515
+ providerActionButtonWrap: "PreferenceApp_providerActionButtonWrap",
3516
+ providerButtonWrap: "PreferenceApp_providerButtonWrap",
3517
+ providerFieldGrid: "PreferenceApp_providerFieldGrid",
3518
+ providerField: "PreferenceApp_providerField",
3519
+ providerFieldLabel: "PreferenceApp_providerFieldLabel",
3520
+ providerSelectWrap: "PreferenceApp_providerSelectWrap",
3521
+ selectWrap: "PreferenceApp_selectWrap",
3522
+ textInput: "PreferenceApp_textInput",
3523
+ numberInput: "PreferenceApp_numberInput",
3524
+ dropdown: "PreferenceApp_dropdown",
3525
+ textInputSensitive: "PreferenceApp_textInput PreferenceApp_textInputSensitive",
3526
+ colorControl: "PreferenceApp_colorControl",
3527
+ colorInput: "PreferenceApp_colorInput",
3528
+ toggle: "PreferenceApp_toggle",
3529
+ toggleInput: "PreferenceApp_toggleInput",
3530
+ toggleTrack: "PreferenceApp_toggleTrack",
3531
+ toggleKnob: "PreferenceApp_toggleKnob",
3532
+ notification: "PreferenceApp_notification",
3533
+ slideUp: "PreferenceApp_slideUp"
3534
+ };
3535
+
3536
+ // desktalk-global:react/jsx-runtime
3537
+ var _mod3 = window.__desktalk_jsx_runtime;
3538
+ var jsx = _mod3.jsx;
3539
+ var jsxs = _mod3.jsxs;
3540
+ var jsxDEV = _mod3.jsxDEV;
3541
+ var Fragment2 = _mod3.Fragment;
3542
+
3543
+ // src/components/PreferenceCategoryList.tsx
3544
+ var CATEGORY_ICONS = {
3545
+ General: "\u2699",
3546
+ Server: "\u{1F310}",
3547
+ AI: "\u{1F916}",
3548
+ Voice: "\u{1F399}"
3549
+ };
3550
+ function PreferenceCategoryList({
3551
+ activeCategory,
3552
+ onSelect,
3553
+ compact = false
3554
+ }) {
3555
+ return /* @__PURE__ */ jsxs("nav", { className: PreferenceApp_default.sidebar, children: [
3556
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.sidebarHeader, children: "Settings" }),
3557
+ CATEGORIES.map((category) => {
3558
+ const button = /* @__PURE__ */ jsxs(
3559
+ "button",
3560
+ {
3561
+ className: category === activeCategory ? PreferenceApp_default.categoryItemActive : PreferenceApp_default.categoryItem,
3562
+ onClick: () => onSelect(category),
3563
+ type: "button",
3564
+ "aria-label": compact ? category : void 0,
3565
+ children: [
3566
+ /* @__PURE__ */ jsx("span", { className: PreferenceApp_default.categoryIcon, children: CATEGORY_ICONS[category] }),
3567
+ !compact && /* @__PURE__ */ jsx("span", { className: PreferenceApp_default.categoryText, children: category })
3568
+ ]
3569
+ },
3570
+ category
3571
+ );
3572
+ if (compact) {
3573
+ return /* @__PURE__ */ jsx("dt-tooltip", { content: category, placement: "bottom", children: button }, category);
3574
+ }
3575
+ return button;
3576
+ })
3577
+ ] });
3578
+ }
3579
+
3580
+ // src/components/AiProviderList.tsx
3581
+ function AiProviderList({ config, onChange }) {
3582
+ const enabledProviders = useMemo(() => {
3583
+ const providers = parseAiEnabledProviders(config["ai.enabledProviders"]);
3584
+ const defaultProvider = typeof config["ai.defaultProvider"] === "string" && config["ai.defaultProvider"] ? String(config["ai.defaultProvider"]) : DEFAULT_AI_PROVIDER_ID;
3585
+ if (!providers.includes(defaultProvider)) {
3586
+ providers.unshift(defaultProvider);
3587
+ }
3588
+ return providers;
3589
+ }, [config]);
3590
+ const updateOrder = useCallback(
3591
+ async (providerIds) => {
3592
+ const nextProviders = providerIds.length > 0 ? providerIds : [DEFAULT_AI_PROVIDER_ID];
3593
+ await onChange("ai.enabledProviders", serializeAiEnabledProviders(nextProviders));
3594
+ await onChange("ai.defaultProvider", nextProviders[0]);
3595
+ },
3596
+ [onChange]
3597
+ );
3598
+ const handleAddProvider = useCallback(async () => {
3599
+ const nextProvider = AI_PROVIDER_DEFINITIONS.find(
3600
+ (provider) => !enabledProviders.includes(provider.id)
3601
+ );
3602
+ if (!nextProvider) {
3603
+ return;
3604
+ }
3605
+ await updateOrder([...enabledProviders, nextProvider.id]);
3606
+ }, [enabledProviders, updateOrder]);
3607
+ const handleProviderChange = useCallback(
3608
+ async (providerId, nextProviderId) => {
3609
+ if (providerId === nextProviderId || enabledProviders.includes(nextProviderId)) {
3610
+ return;
3611
+ }
3612
+ const nextProviders = enabledProviders.map(
3613
+ (currentProviderId) => currentProviderId === providerId ? nextProviderId : currentProviderId
3614
+ );
3615
+ await updateOrder(nextProviders);
3616
+ },
3617
+ [enabledProviders, updateOrder]
3618
+ );
3619
+ const handleDeleteProvider = useCallback(
3620
+ async (providerId) => {
3621
+ if (enabledProviders.length === 1) {
3622
+ return;
3623
+ }
3624
+ const nextProviders = enabledProviders.filter(
3625
+ (currentProviderId) => currentProviderId !== providerId
3626
+ );
3627
+ await updateOrder(nextProviders);
3628
+ for (const key of getAiProviderConfigKeys(providerId)) {
3629
+ await onChange(key, "");
3630
+ }
3631
+ },
3632
+ [enabledProviders, onChange, updateOrder]
3633
+ );
3634
+ const handleSetDefault = useCallback(
3635
+ async (providerId) => {
3636
+ if (enabledProviders[0] === providerId) {
3637
+ return;
3638
+ }
3639
+ const nextProviders = [
3640
+ providerId,
3641
+ ...enabledProviders.filter((currentProviderId) => currentProviderId !== providerId)
3642
+ ];
3643
+ await updateOrder(nextProviders);
3644
+ },
3645
+ [enabledProviders, updateOrder]
3646
+ );
3647
+ return /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerGroup, children: [
3648
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerGroupHeader, children: [
3649
+ /* @__PURE__ */ jsxs("div", { children: [
3650
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.rowLabel, children: "Providers" }),
3651
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.rowDescription, children: "Add providers, keep your default at the top, and remove anything you no longer use." })
3652
+ ] }),
3653
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerActionButtonWrap, children: /* @__PURE__ */ jsx(
3654
+ ProviderButton,
3655
+ {
3656
+ onPress: handleAddProvider,
3657
+ disabled: enabledProviders.length >= AI_PROVIDER_DEFINITIONS.length,
3658
+ variant: "secondary",
3659
+ children: "Add provider"
3660
+ }
3661
+ ) })
3662
+ ] }),
3663
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerList, children: enabledProviders.map((providerId, index) => {
3664
+ const definition = getAiProviderDefinition(providerId);
3665
+ if (!definition) {
3666
+ return null;
3667
+ }
3668
+ const availableOptions = AI_PROVIDER_DEFINITIONS.filter(
3669
+ (provider) => provider.id === providerId || !enabledProviders.includes(provider.id)
3670
+ );
3671
+ return /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerCard, children: /* @__PURE__ */ jsx("dt-card", { variant: "outlined", children: /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerCardBody, children: [
3672
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerCardHeader, children: [
3673
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerCardTitleRow, children: [
3674
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerCardTitle, children: definition.label }),
3675
+ index === 0 && /* @__PURE__ */ jsx("span", { className: PreferenceApp_default.providerDefaultBadge, children: "Default" })
3676
+ ] }),
3677
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerCardActions, children: [
3678
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerButtonWrap, children: /* @__PURE__ */ jsx(
3679
+ ProviderButton,
3680
+ {
3681
+ onPress: () => handleSetDefault(providerId),
3682
+ disabled: index === 0,
3683
+ variant: "secondary",
3684
+ size: "sm",
3685
+ children: "Set as default"
3686
+ }
3687
+ ) }),
3688
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerButtonWrap, children: /* @__PURE__ */ jsx(
3689
+ ProviderButton,
3690
+ {
3691
+ onPress: () => handleDeleteProvider(providerId),
3692
+ disabled: enabledProviders.length === 1,
3693
+ variant: "danger",
3694
+ size: "sm",
3695
+ children: "Delete"
3696
+ }
3697
+ ) })
3698
+ ] })
3699
+ ] }),
3700
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerFieldGrid, children: [
3701
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerField, children: [
3702
+ /* @__PURE__ */ jsx(
3703
+ "label",
3704
+ {
3705
+ className: PreferenceApp_default.providerFieldLabel,
3706
+ htmlFor: `ai-provider-${providerId}`,
3707
+ children: "Provider"
3708
+ }
3709
+ ),
3710
+ /* @__PURE__ */ jsx(
3711
+ ProviderSelect,
3712
+ {
3713
+ value: providerId,
3714
+ options: availableOptions.map((provider) => ({
3715
+ value: provider.id,
3716
+ label: provider.label
3717
+ })),
3718
+ onChange: (nextValue) => handleProviderChange(providerId, nextValue)
3719
+ }
3720
+ )
3721
+ ] }),
3722
+ definition.supportsApiKey && /* @__PURE__ */ jsx(
3723
+ ProviderTextField,
3724
+ {
3725
+ id: `ai-provider-key-${providerId}`,
3726
+ label: "API Key",
3727
+ value: String(config[`ai.providers.${providerId}.apiKey`] ?? ""),
3728
+ sensitive: true,
3729
+ onCommit: (value) => onChange(`ai.providers.${providerId}.apiKey`, value)
3730
+ }
3731
+ ),
3732
+ /* @__PURE__ */ jsx(
3733
+ ProviderTextField,
3734
+ {
3735
+ id: `ai-provider-model-${providerId}`,
3736
+ label: "Model",
3737
+ value: String(config[`ai.providers.${providerId}.model`] ?? ""),
3738
+ onCommit: (value) => onChange(`ai.providers.${providerId}.model`, value)
3739
+ }
3740
+ ),
3741
+ definition.supportsBaseUrl && /* @__PURE__ */ jsx(
3742
+ ProviderTextField,
3743
+ {
3744
+ id: `ai-provider-base-url-${providerId}`,
3745
+ label: "Base URL",
3746
+ value: String(config[`ai.providers.${providerId}.baseUrl`] ?? ""),
3747
+ onCommit: (value) => onChange(`ai.providers.${providerId}.baseUrl`, value)
3748
+ }
3749
+ )
3750
+ ] })
3751
+ ] }) }) }, providerId);
3752
+ }) })
3753
+ ] });
3754
+ }
3755
+ function ProviderButton({
3756
+ children,
3757
+ disabled = false,
3758
+ variant = "primary",
3759
+ size = "md",
3760
+ onPress
3761
+ }) {
3762
+ const [buttonElement, setButtonElement] = useState(null);
3763
+ useEffect(() => {
3764
+ if (!buttonElement) {
3765
+ return;
3766
+ }
3767
+ const handleClick = () => {
3768
+ void onPress();
3769
+ };
3770
+ buttonElement.addEventListener("click", handleClick);
3771
+ return () => buttonElement.removeEventListener("click", handleClick);
3772
+ }, [buttonElement, onPress]);
3773
+ return /* @__PURE__ */ jsx(
3774
+ "dt-button",
3775
+ {
3776
+ ref: (element) => setButtonElement(element),
3777
+ disabled,
3778
+ variant,
3779
+ size,
3780
+ children
3781
+ }
3782
+ );
3783
+ }
3784
+ function ProviderSelect({ value, options, disabled = false, onChange }) {
3785
+ const [selectElement, setSelectElement] = useState(null);
3786
+ useEffect(() => {
3787
+ if (!selectElement) {
3788
+ return;
3789
+ }
3790
+ selectElement.options = options;
3791
+ }, [options, selectElement]);
3792
+ useEffect(() => {
3793
+ if (!selectElement) {
3794
+ return;
3795
+ }
3796
+ selectElement.value = value;
3797
+ }, [selectElement, value]);
3798
+ useEffect(() => {
3799
+ if (!selectElement) {
3800
+ return;
3801
+ }
3802
+ selectElement.disabled = disabled;
3803
+ }, [disabled, selectElement]);
3804
+ useEffect(() => {
3805
+ if (!selectElement) {
3806
+ return;
3807
+ }
3808
+ const handleChange = (event) => {
3809
+ void onChange(event.detail.value);
3810
+ };
3811
+ selectElement.addEventListener("dt-change", handleChange);
3812
+ return () => selectElement.removeEventListener("dt-change", handleChange);
3813
+ }, [onChange, selectElement]);
3814
+ return /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerSelectWrap, children: /* @__PURE__ */ jsx("dt-select", { ref: (element) => setSelectElement(element) }) });
3815
+ }
3816
+ function ProviderTextField({
3817
+ id,
3818
+ label,
3819
+ value,
3820
+ sensitive = false,
3821
+ onCommit
3822
+ }) {
3823
+ const [localValue, setLocalValue] = useState(value);
3824
+ useEffect(() => {
3825
+ setLocalValue(value);
3826
+ }, [value]);
3827
+ const commit = useCallback(() => {
3828
+ if (localValue !== value) {
3829
+ void onCommit(localValue);
3830
+ }
3831
+ }, [localValue, onCommit, value]);
3832
+ return /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerField, children: [
3833
+ /* @__PURE__ */ jsx("label", { className: PreferenceApp_default.providerFieldLabel, htmlFor: id, children: label }),
3834
+ /* @__PURE__ */ jsx(
3835
+ "input",
3836
+ {
3837
+ id,
3838
+ type: sensitive ? "password" : "text",
3839
+ className: sensitive ? PreferenceApp_default.textInputSensitive : PreferenceApp_default.textInput,
3840
+ value: localValue,
3841
+ onChange: (event) => setLocalValue(event.target.value),
3842
+ onBlur: commit,
3843
+ onKeyDown: (event) => {
3844
+ if (event.key === "Enter") {
3845
+ commit();
3846
+ }
3847
+ }
3848
+ }
3849
+ )
3850
+ ] });
3851
+ }
3852
+
3853
+ // src/components/VoiceProviderList.tsx
3854
+ function VoiceProviderList({ config, onChange }) {
3855
+ const enabledProviders = useMemo(() => {
3856
+ const providers = parseVoiceEnabledProviders(config["voice.enabledProviders"]);
3857
+ const defaultProvider = typeof config["voice.defaultProvider"] === "string" && config["voice.defaultProvider"] ? String(config["voice.defaultProvider"]) : DEFAULT_VOICE_PROVIDER_ID;
3858
+ if (!providers.includes(defaultProvider)) {
3859
+ providers.unshift(defaultProvider);
3860
+ }
3861
+ return providers;
3862
+ }, [config]);
3863
+ const updateOrder = useCallback(
3864
+ async (providerIds) => {
3865
+ const nextProviders = providerIds.length > 0 ? providerIds : [DEFAULT_VOICE_PROVIDER_ID];
3866
+ await onChange("voice.enabledProviders", serializeVoiceEnabledProviders(nextProviders));
3867
+ await onChange("voice.defaultProvider", nextProviders[0]);
3868
+ },
3869
+ [onChange]
3870
+ );
3871
+ const handleAddProvider = useCallback(async () => {
3872
+ const nextProvider = VOICE_PROVIDER_DEFINITIONS.find(
3873
+ (provider) => !enabledProviders.includes(provider.id)
3874
+ );
3875
+ if (!nextProvider) {
3876
+ return;
3877
+ }
3878
+ await updateOrder([...enabledProviders, nextProvider.id]);
3879
+ }, [enabledProviders, updateOrder]);
3880
+ const handleProviderChange = useCallback(
3881
+ async (providerId, nextProviderId) => {
3882
+ if (providerId === nextProviderId || enabledProviders.includes(nextProviderId)) {
3883
+ return;
3884
+ }
3885
+ const nextProviders = enabledProviders.map(
3886
+ (currentProviderId) => currentProviderId === providerId ? nextProviderId : currentProviderId
3887
+ );
3888
+ await updateOrder(nextProviders);
3889
+ },
3890
+ [enabledProviders, updateOrder]
3891
+ );
3892
+ const handleDeleteProvider = useCallback(
3893
+ async (providerId) => {
3894
+ if (enabledProviders.length === 1) {
3895
+ return;
3896
+ }
3897
+ const nextProviders = enabledProviders.filter(
3898
+ (currentProviderId) => currentProviderId !== providerId
3899
+ );
3900
+ await updateOrder(nextProviders);
3901
+ for (const key of getVoiceProviderConfigKeys(providerId)) {
3902
+ await onChange(key, "");
3903
+ }
3904
+ },
3905
+ [enabledProviders, onChange, updateOrder]
3906
+ );
3907
+ const handleSetDefault = useCallback(
3908
+ async (providerId) => {
3909
+ if (enabledProviders[0] === providerId) {
3910
+ return;
3911
+ }
3912
+ const nextProviders = [
3913
+ providerId,
3914
+ ...enabledProviders.filter((currentProviderId) => currentProviderId !== providerId)
3915
+ ];
3916
+ await updateOrder(nextProviders);
3917
+ },
3918
+ [enabledProviders, updateOrder]
3919
+ );
3920
+ return /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerGroup, children: [
3921
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerGroupHeader, children: [
3922
+ /* @__PURE__ */ jsxs("div", { children: [
3923
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.rowLabel, children: "Providers" }),
3924
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.rowDescription, children: "Add STT providers, keep your default at the top, and remove unused items." })
3925
+ ] }),
3926
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerActionButtonWrap, children: /* @__PURE__ */ jsx(
3927
+ ProviderButton2,
3928
+ {
3929
+ onPress: handleAddProvider,
3930
+ disabled: enabledProviders.length >= VOICE_PROVIDER_DEFINITIONS.length,
3931
+ variant: "secondary",
3932
+ children: "Add provider"
3933
+ }
3934
+ ) })
3935
+ ] }),
3936
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerList, children: enabledProviders.map((providerId, index) => {
3937
+ const definition = getVoiceProviderDefinition(providerId);
3938
+ if (!definition) {
3939
+ return null;
3940
+ }
3941
+ const availableOptions = VOICE_PROVIDER_DEFINITIONS.filter(
3942
+ (provider) => provider.id === providerId || !enabledProviders.includes(provider.id)
3943
+ );
3944
+ return /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerCard, children: /* @__PURE__ */ jsx("dt-card", { variant: "outlined", children: /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerCardBody, children: [
3945
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerCardHeader, children: [
3946
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerCardTitleRow, children: [
3947
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerCardTitle, children: definition.label }),
3948
+ index === 0 && /* @__PURE__ */ jsx("span", { className: PreferenceApp_default.providerDefaultBadge, children: "Default" })
3949
+ ] }),
3950
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerCardActions, children: [
3951
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerButtonWrap, children: /* @__PURE__ */ jsx(
3952
+ ProviderButton2,
3953
+ {
3954
+ onPress: () => handleSetDefault(providerId),
3955
+ disabled: index === 0,
3956
+ variant: "secondary",
3957
+ size: "sm",
3958
+ children: "Set as default"
3959
+ }
3960
+ ) }),
3961
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerButtonWrap, children: /* @__PURE__ */ jsx(
3962
+ ProviderButton2,
3963
+ {
3964
+ onPress: () => handleDeleteProvider(providerId),
3965
+ disabled: enabledProviders.length === 1,
3966
+ variant: "danger",
3967
+ size: "sm",
3968
+ children: "Delete"
3969
+ }
3970
+ ) })
3971
+ ] })
3972
+ ] }),
3973
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerFieldGrid, children: [
3974
+ /* @__PURE__ */ jsx(
3975
+ ProviderSelectField,
3976
+ {
3977
+ label: "Provider",
3978
+ value: providerId,
3979
+ options: availableOptions.map((provider) => ({
3980
+ value: provider.id,
3981
+ label: provider.label
3982
+ })),
3983
+ onChange: (nextValue) => handleProviderChange(providerId, nextValue)
3984
+ }
3985
+ ),
3986
+ definition.supportsApiKey && /* @__PURE__ */ jsx(
3987
+ ProviderTextField2,
3988
+ {
3989
+ id: `voice-provider-key-${providerId}`,
3990
+ label: "API Key",
3991
+ value: String(config[`voice.providers.${providerId}.apiKey`] ?? ""),
3992
+ sensitive: true,
3993
+ onCommit: (value) => onChange(`voice.providers.${providerId}.apiKey`, value)
3994
+ }
3995
+ ),
3996
+ definition.supportsModel && /* @__PURE__ */ jsx(
3997
+ ProviderTextField2,
3998
+ {
3999
+ id: `voice-provider-model-${providerId}`,
4000
+ label: "Model",
4001
+ value: String(config[`voice.providers.${providerId}.model`] ?? ""),
4002
+ onCommit: (value) => onChange(`voice.providers.${providerId}.model`, value)
4003
+ }
4004
+ ),
4005
+ definition.supportsBaseUrl && /* @__PURE__ */ jsx(
4006
+ ProviderTextField2,
4007
+ {
4008
+ id: `voice-provider-base-url-${providerId}`,
4009
+ label: "Base URL",
4010
+ value: String(config[`voice.providers.${providerId}.baseUrl`] ?? ""),
4011
+ onCommit: (value) => onChange(`voice.providers.${providerId}.baseUrl`, value)
4012
+ }
4013
+ ),
4014
+ definition.supportsAzureDeployment && /* @__PURE__ */ jsx(
4015
+ ProviderTextField2,
4016
+ {
4017
+ id: `voice-provider-deployment-${providerId}`,
4018
+ label: "Azure Deployment",
4019
+ value: String(
4020
+ config[`voice.providers.${providerId}.azureDeployment`] ?? ""
4021
+ ),
4022
+ onCommit: (value) => onChange(`voice.providers.${providerId}.azureDeployment`, value)
4023
+ }
4024
+ ),
4025
+ definition.supportsAzureApiVersion && /* @__PURE__ */ jsx(
4026
+ ProviderTextField2,
4027
+ {
4028
+ id: `voice-provider-api-version-${providerId}`,
4029
+ label: "Azure API Version",
4030
+ value: String(
4031
+ config[`voice.providers.${providerId}.azureApiVersion`] ?? ""
4032
+ ),
4033
+ onCommit: (value) => onChange(`voice.providers.${providerId}.azureApiVersion`, value)
4034
+ }
4035
+ )
4036
+ ] })
4037
+ ] }) }) }, providerId);
4038
+ }) })
4039
+ ] });
4040
+ }
4041
+ function ProviderButton2({
4042
+ children,
4043
+ disabled = false,
4044
+ variant = "primary",
4045
+ size = "md",
4046
+ onPress
4047
+ }) {
4048
+ const [buttonElement, setButtonElement] = useState(null);
4049
+ useEffect(() => {
4050
+ if (!buttonElement) {
4051
+ return;
4052
+ }
4053
+ const handleClick = () => {
4054
+ void onPress();
4055
+ };
4056
+ buttonElement.addEventListener("click", handleClick);
4057
+ return () => buttonElement.removeEventListener("click", handleClick);
4058
+ }, [buttonElement, onPress]);
4059
+ return /* @__PURE__ */ jsx(
4060
+ "dt-button",
4061
+ {
4062
+ ref: (element) => setButtonElement(element),
4063
+ disabled,
4064
+ variant,
4065
+ size,
4066
+ children
4067
+ }
4068
+ );
4069
+ }
4070
+ function ProviderSelectField({
4071
+ label,
4072
+ value,
4073
+ options,
4074
+ onChange
4075
+ }) {
4076
+ const [selectElement, setSelectElement] = useState(null);
4077
+ useEffect(() => {
4078
+ if (!selectElement) {
4079
+ return;
4080
+ }
4081
+ selectElement.options = options;
4082
+ }, [options, selectElement]);
4083
+ useEffect(() => {
4084
+ if (!selectElement) {
4085
+ return;
4086
+ }
4087
+ selectElement.value = value;
4088
+ }, [selectElement, value]);
4089
+ useEffect(() => {
4090
+ if (!selectElement) {
4091
+ return;
4092
+ }
4093
+ const handleChange = (event) => {
4094
+ void onChange(event.detail.value);
4095
+ };
4096
+ selectElement.addEventListener("dt-change", handleChange);
4097
+ return () => selectElement.removeEventListener("dt-change", handleChange);
4098
+ }, [onChange, selectElement]);
4099
+ return /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerField, children: [
4100
+ /* @__PURE__ */ jsx("label", { className: PreferenceApp_default.providerFieldLabel, children: label }),
4101
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.providerSelectWrap, children: /* @__PURE__ */ jsx("dt-select", { ref: (element) => setSelectElement(element) }) })
4102
+ ] });
4103
+ }
4104
+ function ProviderTextField2({
4105
+ id,
4106
+ label,
4107
+ value,
4108
+ sensitive = false,
4109
+ onCommit
4110
+ }) {
4111
+ const [localValue, setLocalValue] = useState(value);
4112
+ useEffect(() => {
4113
+ setLocalValue(value);
4114
+ }, [value]);
4115
+ const commit = useCallback(() => {
4116
+ if (localValue !== value) {
4117
+ void onCommit(localValue);
4118
+ }
4119
+ }, [localValue, onCommit, value]);
4120
+ return /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.providerField, children: [
4121
+ /* @__PURE__ */ jsx("label", { className: PreferenceApp_default.providerFieldLabel, htmlFor: id, children: label }),
4122
+ /* @__PURE__ */ jsx(
4123
+ "input",
4124
+ {
4125
+ id,
4126
+ type: sensitive ? "password" : "text",
4127
+ className: sensitive ? PreferenceApp_default.textInputSensitive : PreferenceApp_default.textInput,
4128
+ value: localValue,
4129
+ onChange: (event) => setLocalValue(event.target.value),
4130
+ onBlur: commit,
4131
+ onKeyDown: (event) => {
4132
+ if (event.key === "Enter") {
4133
+ commit();
4134
+ }
4135
+ }
4136
+ }
4137
+ )
4138
+ ] });
4139
+ }
4140
+
4141
+ // src/components/PreferenceSection.tsx
4142
+ function PreferenceSection({ title, children }) {
4143
+ return /* @__PURE__ */ jsxs("section", { className: PreferenceApp_default.section, children: [
4144
+ /* @__PURE__ */ jsx("h3", { className: PreferenceApp_default.sectionTitle, children: title }),
4145
+ children
4146
+ ] });
4147
+ }
4148
+
4149
+ // src/components/PreferenceRow.tsx
4150
+ function PreferenceRow({ schema, value, onChange }) {
4151
+ return /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.row, children: [
4152
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.rowInfo, children: [
4153
+ /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.rowLabel, children: [
4154
+ schema.label,
4155
+ schema.requiresRestart && /* @__PURE__ */ jsx("span", { className: PreferenceApp_default.rowRestartBadge, children: "restart" })
4156
+ ] }),
4157
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.rowDescription, children: schema.description })
4158
+ ] }),
4159
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.rowControl, children: /* @__PURE__ */ jsx(Control, { schema, value, onChange }) })
4160
+ ] });
4161
+ }
4162
+ function Control({
4163
+ schema,
4164
+ value,
4165
+ onChange
4166
+ }) {
4167
+ if (schema.key === "general.accentColor" && schema.type === "string") {
4168
+ return /* @__PURE__ */ jsx(ColorControl, { schema, value, onChange });
4169
+ }
4170
+ if (schema.type === "boolean") {
4171
+ return /* @__PURE__ */ jsx(ToggleControl, { schema, value, onChange });
4172
+ }
4173
+ if (schema.type === "string" && schema.options) {
4174
+ return /* @__PURE__ */ jsx(DropdownControl, { schema, value, onChange });
4175
+ }
4176
+ if (schema.type === "string") {
4177
+ return /* @__PURE__ */ jsx(TextControl, { schema, value, onChange });
4178
+ }
4179
+ if (schema.type === "number") {
4180
+ return /* @__PURE__ */ jsx(NumberControl, { schema, value, onChange });
4181
+ }
4182
+ return null;
4183
+ }
4184
+ function isHexColor(value) {
4185
+ return /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value);
4186
+ }
4187
+ function ColorControl({
4188
+ schema,
4189
+ value,
4190
+ onChange
4191
+ }) {
4192
+ const [localValue, setLocalValue] = useState(value);
4193
+ useEffect(() => {
4194
+ setLocalValue(value);
4195
+ }, [value]);
4196
+ const commit = useCallback(
4197
+ (nextValue) => {
4198
+ const resolvedValue = (nextValue ?? localValue).trim();
4199
+ if (resolvedValue !== value) {
4200
+ onChange(schema.key, resolvedValue);
4201
+ }
4202
+ },
4203
+ [localValue, onChange, schema.key, value]
4204
+ );
4205
+ const handlePickerInput = useCallback((e) => {
4206
+ setLocalValue(e.currentTarget.value);
4207
+ }, []);
4208
+ const handlePickerChange = useCallback(
4209
+ (e) => {
4210
+ const nextValue = e.target.value;
4211
+ setLocalValue(nextValue);
4212
+ commit(nextValue);
4213
+ },
4214
+ [commit]
4215
+ );
4216
+ const handleTextChange = useCallback((e) => {
4217
+ setLocalValue(e.target.value);
4218
+ }, []);
4219
+ const handleTextKeyDown = useCallback(
4220
+ (e) => {
4221
+ if (e.key === "Enter") {
4222
+ commit();
4223
+ }
4224
+ },
4225
+ [commit]
4226
+ );
4227
+ const handleTextBlur = useCallback(() => {
4228
+ commit();
4229
+ }, [commit]);
4230
+ const pickerValue = isHexColor(localValue) ? localValue : "#7c6ff7";
4231
+ return /* @__PURE__ */ jsxs("div", { className: PreferenceApp_default.colorControl, children: [
4232
+ /* @__PURE__ */ jsx(
4233
+ "input",
4234
+ {
4235
+ type: "color",
4236
+ className: PreferenceApp_default.colorInput,
4237
+ value: pickerValue,
4238
+ onInput: handlePickerInput,
4239
+ onChange: handlePickerChange,
4240
+ "aria-label": `${schema.label} picker`
4241
+ }
4242
+ ),
4243
+ /* @__PURE__ */ jsx(
4244
+ "input",
4245
+ {
4246
+ type: "text",
4247
+ className: PreferenceApp_default.textInput,
4248
+ value: localValue,
4249
+ onChange: handleTextChange,
4250
+ onBlur: handleTextBlur,
4251
+ onKeyDown: handleTextKeyDown,
4252
+ placeholder: "#7c6ff7"
4253
+ }
4254
+ )
4255
+ ] });
4256
+ }
4257
+ function ToggleControl({
4258
+ schema,
4259
+ value,
4260
+ onChange
4261
+ }) {
4262
+ const handleChange = useCallback(() => {
4263
+ onChange(schema.key, !value);
4264
+ }, [schema.key, value, onChange]);
4265
+ return /* @__PURE__ */ jsxs("label", { className: PreferenceApp_default.toggle, children: [
4266
+ /* @__PURE__ */ jsx(
4267
+ "input",
4268
+ {
4269
+ type: "checkbox",
4270
+ className: PreferenceApp_default.toggleInput,
4271
+ checked: value,
4272
+ onChange: handleChange
4273
+ }
4274
+ ),
4275
+ /* @__PURE__ */ jsx("span", { className: PreferenceApp_default.toggleTrack }),
4276
+ /* @__PURE__ */ jsx("span", { className: PreferenceApp_default.toggleKnob })
4277
+ ] });
4278
+ }
4279
+ function DropdownControl({
4280
+ schema,
4281
+ value,
4282
+ onChange
4283
+ }) {
4284
+ const handleChange = useCallback(
4285
+ (nextValue) => {
4286
+ onChange(schema.key, nextValue);
4287
+ },
4288
+ [schema.key, onChange]
4289
+ );
4290
+ return /* @__PURE__ */ jsx(
4291
+ DtSelectControl,
4292
+ {
4293
+ value,
4294
+ options: (schema.options ?? []).map((opt) => ({ value: opt, label: opt })),
4295
+ onChange: handleChange
4296
+ }
4297
+ );
4298
+ }
4299
+ function DtSelectControl({
4300
+ value,
4301
+ options,
4302
+ disabled = false,
4303
+ onChange
4304
+ }) {
4305
+ const [selectElement, setSelectElement] = useState(null);
4306
+ useEffect(() => {
4307
+ if (!selectElement) {
4308
+ return;
4309
+ }
4310
+ selectElement.options = options;
4311
+ }, [options, selectElement]);
4312
+ useEffect(() => {
4313
+ if (!selectElement) {
4314
+ return;
4315
+ }
4316
+ selectElement.value = value;
4317
+ selectElement.disabled = disabled;
4318
+ }, [disabled, selectElement, value]);
4319
+ useEffect(() => {
4320
+ if (!selectElement) {
4321
+ return;
4322
+ }
4323
+ const handleSelectChange = (event) => {
4324
+ onChange(event.detail.value);
4325
+ };
4326
+ selectElement.addEventListener("dt-change", handleSelectChange);
4327
+ return () => selectElement.removeEventListener("dt-change", handleSelectChange);
4328
+ }, [onChange, selectElement]);
4329
+ return /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.selectWrap, children: /* @__PURE__ */ jsx("dt-select", { ref: (element) => setSelectElement(element) }) });
4330
+ }
4331
+ function TextControl({
4332
+ schema,
4333
+ value,
4334
+ onChange
4335
+ }) {
4336
+ const [localValue, setLocalValue] = useState(value);
4337
+ useEffect(() => {
4338
+ setLocalValue(value);
4339
+ }, [value]);
4340
+ const handleBlur = useCallback(() => {
4341
+ if (localValue !== value) {
4342
+ onChange(schema.key, localValue);
4343
+ }
4344
+ }, [schema.key, localValue, value, onChange]);
4345
+ const handleKeyDown = useCallback(
4346
+ (e) => {
4347
+ if (e.key === "Enter") {
4348
+ onChange(schema.key, localValue);
4349
+ }
4350
+ },
4351
+ [schema.key, localValue, onChange]
4352
+ );
4353
+ return /* @__PURE__ */ jsx(
4354
+ "input",
4355
+ {
4356
+ type: schema.sensitive ? "password" : "text",
4357
+ className: schema.sensitive ? PreferenceApp_default.textInputSensitive : PreferenceApp_default.textInput,
4358
+ value: localValue,
4359
+ onChange: (e) => setLocalValue(e.target.value),
4360
+ onBlur: handleBlur,
4361
+ onKeyDown: handleKeyDown,
4362
+ placeholder: schema.sensitive ? "Enter API key..." : void 0
4363
+ }
4364
+ );
4365
+ }
4366
+ function NumberControl({
4367
+ schema,
4368
+ value,
4369
+ onChange
4370
+ }) {
4371
+ const [localValue, setLocalValue] = useState(String(value));
4372
+ useEffect(() => {
4373
+ setLocalValue(String(value));
4374
+ }, [value]);
4375
+ const commit = useCallback(() => {
4376
+ let num = Number(localValue);
4377
+ if (Number.isNaN(num)) {
4378
+ setLocalValue(String(value));
4379
+ return;
4380
+ }
4381
+ if (schema.min !== void 0) num = Math.max(schema.min, num);
4382
+ if (schema.max !== void 0) num = Math.min(schema.max, num);
4383
+ setLocalValue(String(num));
4384
+ if (num !== value) {
4385
+ onChange(schema.key, num);
4386
+ }
4387
+ }, [schema.key, schema.min, schema.max, localValue, value, onChange]);
4388
+ const handleKeyDown = useCallback(
4389
+ (e) => {
4390
+ if (e.key === "Enter") commit();
4391
+ },
4392
+ [commit]
4393
+ );
4394
+ return /* @__PURE__ */ jsx(
4395
+ "input",
4396
+ {
4397
+ type: "number",
4398
+ className: PreferenceApp_default.numberInput,
4399
+ value: localValue,
4400
+ min: schema.min,
4401
+ max: schema.max,
4402
+ onChange: (e) => setLocalValue(e.target.value),
4403
+ onBlur: commit,
4404
+ onKeyDown: handleKeyDown
4405
+ }
4406
+ );
4407
+ }
4408
+
4409
+ // src/components/PreferenceActions.tsx
4410
+ import { ActionsProvider, Action, useCommand } from "@desktalk/sdk";
4411
+ function PreferenceActions({ children, onConfigChanged }) {
4412
+ const getSetting = useCommand(
4413
+ "preferences.get"
4414
+ );
4415
+ const setSetting = useCommand(
4416
+ "preferences.set"
4417
+ );
4418
+ const resetSetting = useCommand("preferences.reset");
4419
+ const resetAllSettings = useCommand("preferences.resetAll");
4420
+ const handleGetSetting = useCallback(
4421
+ async (params) => {
4422
+ const key = params?.key;
4423
+ if (!key) throw new Error("Missing required parameter: key");
4424
+ const result = await getSetting({ key });
4425
+ return result;
4426
+ },
4427
+ [getSetting]
4428
+ );
4429
+ const handleSetSetting = useCallback(
4430
+ async (params) => {
4431
+ const key = params?.key;
4432
+ if (!key) throw new Error("Missing required parameter: key");
4433
+ let value = params?.value;
4434
+ if (value === void 0) throw new Error("Missing required parameter: value");
4435
+ const schema = getSchema(key);
4436
+ if (schema) {
4437
+ if (schema.type === "number" && typeof value === "string") {
4438
+ value = Number(value);
4439
+ } else if (schema.type === "boolean" && typeof value === "string") {
4440
+ value = value === "true";
4441
+ }
4442
+ }
4443
+ await setSetting({ key, value });
4444
+ onConfigChanged();
4445
+ return { success: true };
4446
+ },
4447
+ [setSetting, onConfigChanged]
4448
+ );
4449
+ const handleResetSetting = useCallback(
4450
+ async (params) => {
4451
+ const key = params?.key;
4452
+ if (!key) throw new Error("Missing required parameter: key");
4453
+ await resetSetting({ key });
4454
+ onConfigChanged();
4455
+ return { success: true };
4456
+ },
4457
+ [resetSetting, onConfigChanged]
4458
+ );
4459
+ const handleResetAll = useCallback(async () => {
4460
+ await resetAllSettings();
4461
+ onConfigChanged();
4462
+ return { success: true };
4463
+ }, [resetAllSettings, onConfigChanged]);
4464
+ return /* @__PURE__ */ jsxs(ActionsProvider, { children: [
4465
+ /* @__PURE__ */ jsx(
4466
+ Action,
4467
+ {
4468
+ name: "Get Setting",
4469
+ description: "Read the current value of a setting",
4470
+ params: {
4471
+ key: {
4472
+ type: "string",
4473
+ description: "Setting key (e.g. general.theme)",
4474
+ required: true
4475
+ }
4476
+ },
4477
+ handler: handleGetSetting
4478
+ }
4479
+ ),
4480
+ /* @__PURE__ */ jsx(
4481
+ Action,
4482
+ {
4483
+ name: "Set Setting",
4484
+ description: "Update a setting value",
4485
+ params: {
4486
+ key: {
4487
+ type: "string",
4488
+ description: "Setting key (e.g. general.theme)",
4489
+ required: true
4490
+ },
4491
+ value: {
4492
+ type: "string",
4493
+ description: "New value for the setting",
4494
+ required: true
4495
+ }
4496
+ },
4497
+ handler: handleSetSetting
4498
+ }
4499
+ ),
4500
+ /* @__PURE__ */ jsx(
4501
+ Action,
4502
+ {
4503
+ name: "Reset Setting",
4504
+ description: "Reset a setting to its default value",
4505
+ params: {
4506
+ key: {
4507
+ type: "string",
4508
+ description: "Setting key to reset",
4509
+ required: true
4510
+ }
4511
+ },
4512
+ handler: handleResetSetting
4513
+ }
4514
+ ),
4515
+ /* @__PURE__ */ jsx(
4516
+ Action,
4517
+ {
4518
+ name: "Reset All",
4519
+ description: "Reset all settings to their default values",
4520
+ handler: handleResetAll
4521
+ }
4522
+ ),
4523
+ children
4524
+ ] });
4525
+ }
4526
+
4527
+ // src/frontend.tsx
4528
+ var COMPACT_NAV_WIDTH = 720;
4529
+ function PreferenceApp() {
4530
+ const [config, setConfig] = useState(getDefaultConfig());
4531
+ const [activeCategory, setActiveCategory] = useState(CATEGORIES[0]);
4532
+ const [notification, setNotification] = useState(null);
4533
+ const [compactNav, setCompactNav] = useState(false);
4534
+ const notificationTimer = useRef(null);
4535
+ const rootRef = useRef(null);
4536
+ const getAllSettings = useCommand2("preferences.getAll");
4537
+ const setSetting = useCommand2(
4538
+ "preferences.set"
4539
+ );
4540
+ const fetchConfig = useCallback(async () => {
4541
+ try {
4542
+ const result = await getAllSettings();
4543
+ setConfig(result);
4544
+ } catch (err) {
4545
+ console.error("Failed to load preferences:", err);
4546
+ }
4547
+ }, [getAllSettings]);
4548
+ useEffect(() => {
4549
+ fetchConfig();
4550
+ }, [fetchConfig]);
4551
+ useEffect(() => {
4552
+ if (!rootRef.current) return;
4553
+ const updateLayout = (width) => {
4554
+ setCompactNav(width <= COMPACT_NAV_WIDTH);
4555
+ };
4556
+ updateLayout(rootRef.current.clientWidth);
4557
+ const observer = new ResizeObserver((entries) => {
4558
+ const entry = entries[0];
4559
+ if (!entry) return;
4560
+ updateLayout(entry.contentRect.width);
4561
+ });
4562
+ observer.observe(rootRef.current);
4563
+ return () => observer.disconnect();
4564
+ }, []);
4565
+ useEvent(
4566
+ "preferences:changed",
4567
+ (change) => {
4568
+ setConfig((prev) => ({ ...prev, [change.key]: change.value }));
4569
+ if (change.requiresRestart) {
4570
+ showNotification(
4571
+ __dtLocalize({ scope: "preference", key: "notifications.restartRequired", defaultText: "This change requires a restart to take effect." })
4572
+ );
4573
+ }
4574
+ }
4575
+ );
4576
+ useEvent("preferences:resetAll", () => {
4577
+ fetchConfig();
4578
+ showNotification(__dtLocalize({ scope: "preference", key: "notifications.resetAll", defaultText: "All settings have been reset to defaults." }));
4579
+ });
4580
+ const showNotification = useCallback((message) => {
4581
+ setNotification(message);
4582
+ if (notificationTimer.current) clearTimeout(notificationTimer.current);
4583
+ notificationTimer.current = setTimeout(() => setNotification(null), 4e3);
4584
+ }, []);
4585
+ const handleChange = useCallback(
4586
+ async (key, value) => {
4587
+ setConfig((prev) => ({ ...prev, [key]: value }));
4588
+ try {
4589
+ await setSetting({ key, value });
4590
+ } catch (err) {
4591
+ console.error(`Failed to update ${key}:`, err);
4592
+ fetchConfig();
4593
+ }
4594
+ },
4595
+ [setSetting, fetchConfig]
4596
+ );
4597
+ const categoriesToShow = CATEGORIES.filter((c) => c === activeCategory);
4598
+ const getVisibleSchemas = useCallback((category) => {
4599
+ const schemas = getSchemasByCategory(category);
4600
+ if (category !== "AI" && category !== "Voice") {
4601
+ return schemas;
4602
+ }
4603
+ return schemas.filter((schema) => {
4604
+ if (category === "AI") {
4605
+ return !schema.key.startsWith("ai.providers.") && schema.key !== "ai.defaultProvider" && schema.key !== "ai.enabledProviders";
4606
+ }
4607
+ return !schema.key.startsWith("voice.providers.") && schema.key !== "voice.defaultProvider" && schema.key !== "voice.enabledProviders";
4608
+ });
4609
+ }, []);
4610
+ return /* @__PURE__ */ jsx(PreferenceActions, { onConfigChanged: fetchConfig, children: /* @__PURE__ */ jsxs("div", { ref: rootRef, className: `${PreferenceApp_default.root}${compactNav ? ` ${PreferenceApp_default.rootCompact}` : ""}`, children: [
4611
+ /* @__PURE__ */ jsx(
4612
+ PreferenceCategoryList,
4613
+ {
4614
+ activeCategory,
4615
+ onSelect: setActiveCategory,
4616
+ compact: compactNav
4617
+ }
4618
+ ),
4619
+ /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.settingsPanel, children: categoriesToShow.map((category) => {
4620
+ const schemas = getVisibleSchemas(category);
4621
+ return /* @__PURE__ */ jsxs(PreferenceSection, { title: category, children: [
4622
+ category === "AI" && /* @__PURE__ */ jsx(AiProviderList, { config, onChange: handleChange }),
4623
+ category === "Voice" && /* @__PURE__ */ jsx(VoiceProviderList, { config, onChange: handleChange }),
4624
+ schemas.map((schema) => /* @__PURE__ */ jsx(
4625
+ PreferenceRow,
4626
+ {
4627
+ schema,
4628
+ value: config[schema.key] ?? schema.default,
4629
+ onChange: handleChange
4630
+ },
4631
+ schema.key
4632
+ ))
4633
+ ] }, category);
4634
+ }) }),
4635
+ notification && /* @__PURE__ */ jsx("div", { className: PreferenceApp_default.notification, children: notification })
4636
+ ] }) });
4637
+ }
4638
+ function activate(ctx) {
4639
+ const root = createRoot(ctx.root);
4640
+ root.render(
4641
+ /* @__PURE__ */ jsx(WindowIdProvider, { windowId: ctx.windowId, children: /* @__PURE__ */ jsx(MiniAppIdProvider, { miniAppId: ctx.miniAppId, children: /* @__PURE__ */ jsx(PreferenceApp, {}) }) })
4642
+ );
4643
+ return {
4644
+ deactivate() {
4645
+ root.unmount();
4646
+ }
4647
+ };
4648
+ }
4649
+ export {
4650
+ activate
4651
+ };
4652
+ //# sourceMappingURL=frontend.js.map