tjs-lang 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTEXT.md +594 -0
- package/LICENSE +190 -0
- package/README.md +220 -0
- package/bin/benchmarks.ts +351 -0
- package/bin/dev.ts +205 -0
- package/bin/docs.js +170 -0
- package/bin/install-cursor.sh +71 -0
- package/bin/install-vscode.sh +71 -0
- package/bin/select-local-models.d.ts +1 -0
- package/bin/select-local-models.js +28 -0
- package/bin/select-local-models.ts +31 -0
- package/demo/autocomplete.test.ts +232 -0
- package/demo/docs.json +186 -0
- package/demo/examples.test.ts +598 -0
- package/demo/index.html +91 -0
- package/demo/src/autocomplete.ts +482 -0
- package/demo/src/capabilities.ts +859 -0
- package/demo/src/demo-nav.ts +2097 -0
- package/demo/src/examples.test.ts +161 -0
- package/demo/src/examples.ts +476 -0
- package/demo/src/imports.test.ts +196 -0
- package/demo/src/imports.ts +421 -0
- package/demo/src/index.ts +639 -0
- package/demo/src/module-store.ts +635 -0
- package/demo/src/module-sw.ts +132 -0
- package/demo/src/playground.ts +949 -0
- package/demo/src/service-host.ts +389 -0
- package/demo/src/settings.ts +440 -0
- package/demo/src/style.ts +280 -0
- package/demo/src/tjs-playground.ts +1605 -0
- package/demo/src/ts-examples.ts +478 -0
- package/demo/src/ts-playground.ts +1092 -0
- package/demo/static/favicon.svg +30 -0
- package/demo/static/photo-1.jpg +0 -0
- package/demo/static/photo-2.jpg +0 -0
- package/demo/static/texts/ai-history.txt +9 -0
- package/demo/static/texts/coffee-origins.txt +9 -0
- package/demo/static/texts/renewable-energy.txt +9 -0
- package/dist/index.js +256 -0
- package/dist/index.js.map +37 -0
- package/dist/tjs-batteries.js +4 -0
- package/dist/tjs-batteries.js.map +15 -0
- package/dist/tjs-full.js +256 -0
- package/dist/tjs-full.js.map +37 -0
- package/dist/tjs-transpiler.js +220 -0
- package/dist/tjs-transpiler.js.map +21 -0
- package/dist/tjs-vm.js +4 -0
- package/dist/tjs-vm.js.map +14 -0
- package/docs/CNAME +1 -0
- package/docs/favicon.svg +30 -0
- package/docs/index.html +91 -0
- package/docs/index.js +10468 -0
- package/docs/index.js.map +92 -0
- package/docs/photo-1.jpg +0 -0
- package/docs/photo-1.webp +0 -0
- package/docs/photo-2.jpg +0 -0
- package/docs/photo-2.webp +0 -0
- package/docs/texts/ai-history.txt +9 -0
- package/docs/texts/coffee-origins.txt +9 -0
- package/docs/texts/renewable-energy.txt +9 -0
- package/docs/tjs-lang.svg +31 -0
- package/docs/tosijs-agent.svg +31 -0
- package/editors/README.md +325 -0
- package/editors/ace/ajs-mode.js +328 -0
- package/editors/ace/ajs-mode.ts +269 -0
- package/editors/ajs-syntax.ts +212 -0
- package/editors/build-grammars.ts +510 -0
- package/editors/codemirror/ajs-language.js +287 -0
- package/editors/codemirror/ajs-language.ts +1447 -0
- package/editors/codemirror/autocomplete.test.ts +531 -0
- package/editors/codemirror/component.ts +404 -0
- package/editors/monaco/ajs-monarch.js +243 -0
- package/editors/monaco/ajs-monarch.ts +225 -0
- package/editors/tjs-syntax.ts +115 -0
- package/editors/vscode/language-configuration.json +37 -0
- package/editors/vscode/package.json +65 -0
- package/editors/vscode/syntaxes/ajs-injection.tmLanguage.json +107 -0
- package/editors/vscode/syntaxes/ajs.tmLanguage.json +252 -0
- package/editors/vscode/syntaxes/tjs.tmLanguage.json +333 -0
- package/package.json +83 -0
- package/src/cli/commands/check.ts +41 -0
- package/src/cli/commands/convert.ts +133 -0
- package/src/cli/commands/emit.ts +260 -0
- package/src/cli/commands/run.ts +68 -0
- package/src/cli/commands/test.ts +194 -0
- package/src/cli/commands/types.ts +20 -0
- package/src/cli/create-app.ts +236 -0
- package/src/cli/playground.ts +250 -0
- package/src/cli/tjs.ts +166 -0
- package/src/cli/tjsx.ts +160 -0
- package/tjs-lang.svg +31 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* settings.ts - Settings dialog for API keys and preferences
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { elements, vars, Component, StyleSheet } from 'tosijs'
|
|
6
|
+
|
|
7
|
+
import { icons } from 'tosijs-ui'
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
rescanLocalModels,
|
|
11
|
+
checkServerLoad,
|
|
12
|
+
getPendingRequests,
|
|
13
|
+
} from './capabilities'
|
|
14
|
+
|
|
15
|
+
const { div, button, span, label, input, h2, p, select, option } = elements
|
|
16
|
+
|
|
17
|
+
// Settings dialog styles
|
|
18
|
+
StyleSheet('settings-styles', {
|
|
19
|
+
'.settings-overlay': {
|
|
20
|
+
position: 'fixed',
|
|
21
|
+
top: 0,
|
|
22
|
+
left: 0,
|
|
23
|
+
right: 0,
|
|
24
|
+
bottom: 0,
|
|
25
|
+
background: 'rgba(0, 0, 0, 0.5)',
|
|
26
|
+
display: 'flex',
|
|
27
|
+
alignItems: 'center',
|
|
28
|
+
justifyContent: 'center',
|
|
29
|
+
zIndex: 1000,
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
'.settings-dialog': {
|
|
33
|
+
background: vars.background,
|
|
34
|
+
borderRadius: vars.borderRadius,
|
|
35
|
+
padding: vars.spacing200,
|
|
36
|
+
maxWidth: '500px',
|
|
37
|
+
width: '90%',
|
|
38
|
+
maxHeight: '80vh',
|
|
39
|
+
overflow: 'auto',
|
|
40
|
+
boxShadow: '0 10px 40px rgba(0, 0, 0, 0.3)',
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
'.settings-header': {
|
|
44
|
+
display: 'flex',
|
|
45
|
+
alignItems: 'center',
|
|
46
|
+
justifyContent: 'space-between',
|
|
47
|
+
marginBottom: vars.spacing,
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
'.settings-header h2': {
|
|
51
|
+
margin: 0,
|
|
52
|
+
fontSize: '1.25em',
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
'.settings-section': {
|
|
56
|
+
marginBottom: vars.spacing200,
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
'.settings-section h3': {
|
|
60
|
+
fontSize: '1em',
|
|
61
|
+
marginBottom: vars.spacing,
|
|
62
|
+
color: vars.brandColor,
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
'.settings-field': {
|
|
66
|
+
marginBottom: vars.spacing,
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
'.settings-field label': {
|
|
70
|
+
display: 'block',
|
|
71
|
+
marginBottom: '4px',
|
|
72
|
+
fontSize: '0.9em',
|
|
73
|
+
fontWeight: 500,
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
'.settings-field input': {
|
|
77
|
+
width: '100%',
|
|
78
|
+
padding: '8px 12px',
|
|
79
|
+
border: `1px solid ${vars.codeBorder}`,
|
|
80
|
+
borderRadius: vars.borderRadius,
|
|
81
|
+
background: vars.background,
|
|
82
|
+
color: vars.textColor,
|
|
83
|
+
fontSize: 'inherit',
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
'.settings-field input:focus': {
|
|
87
|
+
outline: 'none',
|
|
88
|
+
borderColor: vars.brandColor,
|
|
89
|
+
boxShadow: `0 0 0 2px rgba(99, 102, 241, 0.2)`,
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
'.settings-field .hint': {
|
|
93
|
+
fontSize: '0.8em',
|
|
94
|
+
color: vars.textColor,
|
|
95
|
+
opacity: 0.7,
|
|
96
|
+
marginTop: '4px',
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
'.settings-actions': {
|
|
100
|
+
display: 'flex',
|
|
101
|
+
justifyContent: 'flex-end',
|
|
102
|
+
gap: vars.spacing,
|
|
103
|
+
marginTop: vars.spacing200,
|
|
104
|
+
paddingTop: vars.spacing,
|
|
105
|
+
borderTop: `1px solid ${vars.codeBorder}`,
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
'.settings-btn': {
|
|
109
|
+
padding: '8px 16px',
|
|
110
|
+
borderRadius: vars.borderRadius,
|
|
111
|
+
border: 'none',
|
|
112
|
+
cursor: 'pointer',
|
|
113
|
+
fontWeight: 500,
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
'.settings-btn.primary': {
|
|
117
|
+
background: vars.brandColor,
|
|
118
|
+
color: 'white',
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
'.settings-btn.secondary': {
|
|
122
|
+
background: vars.codeBackground,
|
|
123
|
+
color: vars.textColor,
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
export type LLMProvider =
|
|
128
|
+
| 'auto'
|
|
129
|
+
| 'custom'
|
|
130
|
+
| 'openai'
|
|
131
|
+
| 'anthropic'
|
|
132
|
+
| 'deepseek'
|
|
133
|
+
|
|
134
|
+
export interface SettingsData {
|
|
135
|
+
preferredProvider: LLMProvider
|
|
136
|
+
openaiKey: string
|
|
137
|
+
anthropicKey: string
|
|
138
|
+
deepseekKey: string
|
|
139
|
+
customLlmUrl: string
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function showSettingsDialog(
|
|
143
|
+
currentSettings: SettingsData,
|
|
144
|
+
onSave: (settings: SettingsData) => void
|
|
145
|
+
): void {
|
|
146
|
+
const overlay = div({ class: 'settings-overlay' })
|
|
147
|
+
|
|
148
|
+
const providerSelect = select(
|
|
149
|
+
{ style: { width: '100%', padding: '8px 12px', borderRadius: '6px' } },
|
|
150
|
+
option(
|
|
151
|
+
{ value: 'auto', selected: currentSettings.preferredProvider === 'auto' },
|
|
152
|
+
'First Available'
|
|
153
|
+
),
|
|
154
|
+
option(
|
|
155
|
+
{
|
|
156
|
+
value: 'custom',
|
|
157
|
+
selected: currentSettings.preferredProvider === 'custom',
|
|
158
|
+
},
|
|
159
|
+
'Custom Endpoint (LM Studio, Ollama)'
|
|
160
|
+
),
|
|
161
|
+
option(
|
|
162
|
+
{
|
|
163
|
+
value: 'openai',
|
|
164
|
+
selected: currentSettings.preferredProvider === 'openai',
|
|
165
|
+
},
|
|
166
|
+
'OpenAI'
|
|
167
|
+
),
|
|
168
|
+
option(
|
|
169
|
+
{
|
|
170
|
+
value: 'anthropic',
|
|
171
|
+
selected: currentSettings.preferredProvider === 'anthropic',
|
|
172
|
+
},
|
|
173
|
+
'Anthropic'
|
|
174
|
+
),
|
|
175
|
+
option(
|
|
176
|
+
{
|
|
177
|
+
value: 'deepseek',
|
|
178
|
+
selected: currentSettings.preferredProvider === 'deepseek',
|
|
179
|
+
},
|
|
180
|
+
'Deepseek'
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
const openaiInput = input({
|
|
185
|
+
type: 'password',
|
|
186
|
+
placeholder: 'sk-...',
|
|
187
|
+
value: currentSettings.openaiKey,
|
|
188
|
+
autocomplete: 'off',
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
const anthropicInput = input({
|
|
192
|
+
type: 'password',
|
|
193
|
+
placeholder: 'sk-ant-...',
|
|
194
|
+
value: currentSettings.anthropicKey,
|
|
195
|
+
autocomplete: 'off',
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
const deepseekInput = input({
|
|
199
|
+
type: 'password',
|
|
200
|
+
placeholder: 'sk-...',
|
|
201
|
+
value: currentSettings.deepseekKey,
|
|
202
|
+
autocomplete: 'off',
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
const customUrlInput = input({
|
|
206
|
+
type: 'url',
|
|
207
|
+
placeholder: 'http://localhost:1234/v1',
|
|
208
|
+
value: currentSettings.customLlmUrl,
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
const close = () => {
|
|
212
|
+
overlay.remove()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const save = () => {
|
|
216
|
+
onSave({
|
|
217
|
+
preferredProvider: (providerSelect as HTMLSelectElement)
|
|
218
|
+
.value as LLMProvider,
|
|
219
|
+
openaiKey: (openaiInput as HTMLInputElement).value,
|
|
220
|
+
anthropicKey: (anthropicInput as HTMLInputElement).value,
|
|
221
|
+
deepseekKey: (deepseekInput as HTMLInputElement).value,
|
|
222
|
+
customLlmUrl: (customUrlInput as HTMLInputElement).value,
|
|
223
|
+
})
|
|
224
|
+
close()
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
overlay.append(
|
|
228
|
+
div(
|
|
229
|
+
{ class: 'settings-dialog' },
|
|
230
|
+
// Header
|
|
231
|
+
div(
|
|
232
|
+
{ class: 'settings-header' },
|
|
233
|
+
h2('Settings'),
|
|
234
|
+
button(
|
|
235
|
+
{
|
|
236
|
+
class: 'iconic',
|
|
237
|
+
onClick: close,
|
|
238
|
+
},
|
|
239
|
+
icons.x()
|
|
240
|
+
)
|
|
241
|
+
),
|
|
242
|
+
|
|
243
|
+
// LLM API Keys section
|
|
244
|
+
div(
|
|
245
|
+
{ class: 'settings-section' },
|
|
246
|
+
div(
|
|
247
|
+
{ style: { fontWeight: 600, marginBottom: '10px' } },
|
|
248
|
+
'LLM Settings'
|
|
249
|
+
),
|
|
250
|
+
p(
|
|
251
|
+
{ style: { fontSize: '0.85em', opacity: 0.8, marginBottom: '15px' } },
|
|
252
|
+
'API keys are stored locally in your browser and never sent to any server except the respective API provider.'
|
|
253
|
+
),
|
|
254
|
+
|
|
255
|
+
div(
|
|
256
|
+
{ class: 'settings-field' },
|
|
257
|
+
label('Preferred Provider'),
|
|
258
|
+
providerSelect,
|
|
259
|
+
div(
|
|
260
|
+
{ class: 'hint' },
|
|
261
|
+
'"First Available" uses the first configured provider in order below'
|
|
262
|
+
)
|
|
263
|
+
),
|
|
264
|
+
|
|
265
|
+
div(
|
|
266
|
+
{ class: 'settings-field' },
|
|
267
|
+
label('Custom LLM Endpoint'),
|
|
268
|
+
customUrlInput,
|
|
269
|
+
div(
|
|
270
|
+
{ class: 'hint' },
|
|
271
|
+
'OpenAI-compatible endpoint (e.g., LM Studio, Ollama). ',
|
|
272
|
+
window.location.protocol === 'https:'
|
|
273
|
+
? span(
|
|
274
|
+
{ style: { color: '#dc2626' } },
|
|
275
|
+
'Note: Local endpoints require HTTP.'
|
|
276
|
+
)
|
|
277
|
+
: ''
|
|
278
|
+
),
|
|
279
|
+
div(
|
|
280
|
+
{
|
|
281
|
+
style: {
|
|
282
|
+
marginTop: '8px',
|
|
283
|
+
display: 'flex',
|
|
284
|
+
alignItems: 'center',
|
|
285
|
+
gap: '10px',
|
|
286
|
+
flexWrap: 'wrap',
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
button(
|
|
290
|
+
{
|
|
291
|
+
class: 'settings-btn secondary',
|
|
292
|
+
style: { padding: '4px 10px', fontSize: '0.85em' },
|
|
293
|
+
onClick: async (e: Event) => {
|
|
294
|
+
const btn = e.target as HTMLButtonElement
|
|
295
|
+
const container = btn.parentElement as HTMLElement
|
|
296
|
+
const statusEl = container.querySelector(
|
|
297
|
+
'.status-text'
|
|
298
|
+
) as HTMLElement
|
|
299
|
+
btn.disabled = true
|
|
300
|
+
btn.textContent = 'Scanning...'
|
|
301
|
+
statusEl.textContent = ''
|
|
302
|
+
|
|
303
|
+
const url = (customUrlInput as HTMLInputElement).value
|
|
304
|
+
const models = await rescanLocalModels(url)
|
|
305
|
+
|
|
306
|
+
btn.disabled = false
|
|
307
|
+
btn.textContent = 'Rescan Models'
|
|
308
|
+
|
|
309
|
+
if (models.length > 0) {
|
|
310
|
+
const visionModels = models.filter(
|
|
311
|
+
(m) =>
|
|
312
|
+
m.includes('-vl') ||
|
|
313
|
+
m.includes('vl-') ||
|
|
314
|
+
m.includes('vision') ||
|
|
315
|
+
m.includes('llava') ||
|
|
316
|
+
m.includes('gemma-3') ||
|
|
317
|
+
m.includes('gemma3')
|
|
318
|
+
)
|
|
319
|
+
statusEl.textContent =
|
|
320
|
+
`Found ${models.length} model(s)` +
|
|
321
|
+
(visionModels.length > 0
|
|
322
|
+
? ` (${visionModels.length} vision)`
|
|
323
|
+
: '')
|
|
324
|
+
statusEl.style.color = '#16a34a'
|
|
325
|
+
} else {
|
|
326
|
+
statusEl.textContent = 'No models found'
|
|
327
|
+
statusEl.style.color = '#dc2626'
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
'Rescan Models'
|
|
332
|
+
),
|
|
333
|
+
button(
|
|
334
|
+
{
|
|
335
|
+
class: 'settings-btn secondary',
|
|
336
|
+
style: { padding: '4px 10px', fontSize: '0.85em' },
|
|
337
|
+
onClick: async (e: Event) => {
|
|
338
|
+
const btn = e.target as HTMLButtonElement
|
|
339
|
+
const container = btn.parentElement as HTMLElement
|
|
340
|
+
const statusEl = container.querySelector(
|
|
341
|
+
'.status-text'
|
|
342
|
+
) as HTMLElement
|
|
343
|
+
btn.disabled = true
|
|
344
|
+
btn.textContent = 'Checking...'
|
|
345
|
+
|
|
346
|
+
const url = (customUrlInput as HTMLInputElement).value
|
|
347
|
+
if (!url) {
|
|
348
|
+
statusEl.textContent = 'No URL configured'
|
|
349
|
+
statusEl.style.color = '#dc2626'
|
|
350
|
+
btn.disabled = false
|
|
351
|
+
btn.textContent = 'Check Status'
|
|
352
|
+
return
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const isResponsive = await checkServerLoad(url)
|
|
356
|
+
const pending = getPendingRequests(url)
|
|
357
|
+
|
|
358
|
+
btn.disabled = false
|
|
359
|
+
btn.textContent = 'Check Status'
|
|
360
|
+
|
|
361
|
+
if (isResponsive) {
|
|
362
|
+
statusEl.textContent =
|
|
363
|
+
pending > 0 ? `Ready (${pending} pending)` : 'Ready'
|
|
364
|
+
statusEl.style.color = '#16a34a'
|
|
365
|
+
} else {
|
|
366
|
+
statusEl.textContent =
|
|
367
|
+
pending > 0
|
|
368
|
+
? `Under load (${pending} pending)`
|
|
369
|
+
: 'Under load or unreachable'
|
|
370
|
+
statusEl.style.color = '#f59e0b'
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
'Check Status'
|
|
375
|
+
),
|
|
376
|
+
span({ class: 'status-text', style: { fontSize: '0.85em' } }, '')
|
|
377
|
+
)
|
|
378
|
+
),
|
|
379
|
+
|
|
380
|
+
div(
|
|
381
|
+
{ class: 'settings-field' },
|
|
382
|
+
label('OpenAI API Key'),
|
|
383
|
+
openaiInput,
|
|
384
|
+
div({ class: 'hint' }, 'For GPT-4, GPT-3.5, etc.')
|
|
385
|
+
),
|
|
386
|
+
|
|
387
|
+
div(
|
|
388
|
+
{ class: 'settings-field' },
|
|
389
|
+
label('Anthropic API Key'),
|
|
390
|
+
anthropicInput,
|
|
391
|
+
div({ class: 'hint' }, 'For Claude models')
|
|
392
|
+
),
|
|
393
|
+
|
|
394
|
+
div(
|
|
395
|
+
{ class: 'settings-field' },
|
|
396
|
+
label('Deepseek API Key'),
|
|
397
|
+
deepseekInput,
|
|
398
|
+
div({ class: 'hint' }, 'For Deepseek models (cheap & capable)')
|
|
399
|
+
)
|
|
400
|
+
),
|
|
401
|
+
|
|
402
|
+
// Actions
|
|
403
|
+
div(
|
|
404
|
+
{ class: 'settings-actions' },
|
|
405
|
+
button(
|
|
406
|
+
{
|
|
407
|
+
class: 'settings-btn secondary',
|
|
408
|
+
onClick: close,
|
|
409
|
+
},
|
|
410
|
+
'Cancel'
|
|
411
|
+
),
|
|
412
|
+
button(
|
|
413
|
+
{
|
|
414
|
+
class: 'settings-btn primary',
|
|
415
|
+
onClick: save,
|
|
416
|
+
},
|
|
417
|
+
'Save'
|
|
418
|
+
)
|
|
419
|
+
)
|
|
420
|
+
)
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
// Close on overlay click
|
|
424
|
+
overlay.addEventListener('click', (e) => {
|
|
425
|
+
if (e.target === overlay) {
|
|
426
|
+
close()
|
|
427
|
+
}
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
// Close on Escape
|
|
431
|
+
const handleEscape = (e: KeyboardEvent) => {
|
|
432
|
+
if (e.key === 'Escape') {
|
|
433
|
+
close()
|
|
434
|
+
document.removeEventListener('keydown', handleEscape)
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
document.addEventListener('keydown', handleEscape)
|
|
438
|
+
|
|
439
|
+
document.body.append(overlay)
|
|
440
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* style.ts - CSS styles for agent-99 demo site
|
|
3
|
+
*
|
|
4
|
+
* Uses tosijs StyleSheet with CSS variables for theming.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { vars } from 'tosijs'
|
|
8
|
+
|
|
9
|
+
// Brand colors
|
|
10
|
+
const brandColor = '#3d4a6b' // Dark muted blue
|
|
11
|
+
const brandTextColor = '#ffffff'
|
|
12
|
+
|
|
13
|
+
// Extend CSS variables
|
|
14
|
+
export const styleSpec = {
|
|
15
|
+
':root': {
|
|
16
|
+
_brandColor: brandColor,
|
|
17
|
+
_brandTextColor: brandTextColor,
|
|
18
|
+
_headerHeight: '50px',
|
|
19
|
+
_sidebarWidth: '220px',
|
|
20
|
+
_spacing: '10px',
|
|
21
|
+
_spacing50: '5px',
|
|
22
|
+
_spacing200: '20px',
|
|
23
|
+
_borderRadius: '6px',
|
|
24
|
+
_fontMono: "'SF Mono', Monaco, 'Cascadia Code', Consolas, monospace",
|
|
25
|
+
_fontSize: '15px',
|
|
26
|
+
_lineHeight: '1.6',
|
|
27
|
+
_xinTabsSelectedColor: vars.brandColor,
|
|
28
|
+
// Light mode colors
|
|
29
|
+
_background: '#ffffff',
|
|
30
|
+
_textColor: '#1f2937',
|
|
31
|
+
_codeBackground: '#f3f4f6',
|
|
32
|
+
_codeBorder: '#e5e7eb',
|
|
33
|
+
_linkColor: brandColor,
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// Dark mode - explicit colors for better control
|
|
37
|
+
'.darkmode': {
|
|
38
|
+
_background: '#111827',
|
|
39
|
+
_textColor: '#f3f4f6',
|
|
40
|
+
_codeBackground: '#1f2937',
|
|
41
|
+
_codeBorder: '#374151',
|
|
42
|
+
_linkColor: '#818cf8',
|
|
43
|
+
// xin-tabs uses these
|
|
44
|
+
_xinTabsBarColor: '#374151',
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// High contrast mode - uses filter for comprehensive contrast boost
|
|
48
|
+
'.high-contrast': {
|
|
49
|
+
filter: 'contrast(1.4)',
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// Base styles
|
|
53
|
+
'html, body': {
|
|
54
|
+
margin: 0,
|
|
55
|
+
padding: 0,
|
|
56
|
+
height: '100%',
|
|
57
|
+
fontFamily:
|
|
58
|
+
"system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
|
|
59
|
+
fontSize: vars.fontSize,
|
|
60
|
+
lineHeight: vars.lineHeight,
|
|
61
|
+
background: vars.background,
|
|
62
|
+
color: vars.textColor,
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
body: {
|
|
66
|
+
display: 'flex',
|
|
67
|
+
flexDirection: 'column',
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
main: {
|
|
71
|
+
flex: '1',
|
|
72
|
+
display: 'flex',
|
|
73
|
+
flexDirection: 'column',
|
|
74
|
+
overflow: 'hidden',
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// Header
|
|
78
|
+
header: {
|
|
79
|
+
display: 'flex',
|
|
80
|
+
alignItems: 'center',
|
|
81
|
+
height: vars.headerHeight,
|
|
82
|
+
padding: `0 ${vars.spacing}`,
|
|
83
|
+
background: vars.brandColor,
|
|
84
|
+
color: vars.brandTextColor,
|
|
85
|
+
gap: vars.spacing,
|
|
86
|
+
flexShrink: 0,
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
'header h1': {
|
|
90
|
+
margin: 0,
|
|
91
|
+
fontSize: '1.25em',
|
|
92
|
+
fontWeight: 600,
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
'header a': {
|
|
96
|
+
color: vars.brandTextColor,
|
|
97
|
+
textDecoration: 'none',
|
|
98
|
+
display: 'flex',
|
|
99
|
+
alignItems: 'center',
|
|
100
|
+
gap: vars.spacing50,
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
'header .elastic': {
|
|
104
|
+
flex: '1 1 auto',
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
// Icon buttons
|
|
108
|
+
'.iconic': {
|
|
109
|
+
background: 'none',
|
|
110
|
+
border: 'none',
|
|
111
|
+
cursor: 'pointer',
|
|
112
|
+
padding: vars.spacing50,
|
|
113
|
+
borderRadius: vars.borderRadius,
|
|
114
|
+
color: 'inherit',
|
|
115
|
+
display: 'flex',
|
|
116
|
+
alignItems: 'center',
|
|
117
|
+
justifyContent: 'center',
|
|
118
|
+
transition: 'background 0.15s',
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
'.iconic:hover': {
|
|
122
|
+
background: 'rgba(255, 255, 255, 0.15)',
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
// Links
|
|
126
|
+
a: {
|
|
127
|
+
color: vars.linkColor,
|
|
128
|
+
textDecoration: 'none',
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
'a:hover': {
|
|
132
|
+
textDecoration: 'underline',
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
// Doc links in sidebar
|
|
136
|
+
'.doc-link': {
|
|
137
|
+
display: 'block',
|
|
138
|
+
padding: `${vars.spacing50} ${vars.spacing}`,
|
|
139
|
+
color: vars.textColor,
|
|
140
|
+
borderRadius: vars.borderRadius,
|
|
141
|
+
textDecoration: 'none',
|
|
142
|
+
transition: 'background 0.15s',
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
'.doc-link:hover': {
|
|
146
|
+
background: 'rgba(99, 102, 241, 0.1)',
|
|
147
|
+
textDecoration: 'none',
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
'.doc-link.current': {
|
|
151
|
+
background: vars.brandColor,
|
|
152
|
+
color: vars.brandTextColor,
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
// Code blocks (exclude CodeMirror)
|
|
156
|
+
'pre:not(.cm-content), code:not(.cm-content code)': {
|
|
157
|
+
fontFamily: vars.fontMono,
|
|
158
|
+
fontSize: '0.9em',
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
'pre:not(.cm-content)': {
|
|
162
|
+
background: vars.codeBackground,
|
|
163
|
+
border: `1px solid ${vars.codeBorder}`,
|
|
164
|
+
borderRadius: vars.borderRadius,
|
|
165
|
+
padding: vars.spacing,
|
|
166
|
+
overflow: 'auto',
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
// CodeMirror fixes
|
|
170
|
+
'.cm-editor': {
|
|
171
|
+
height: '100%',
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
'code:not(pre code)': {
|
|
175
|
+
background: vars.codeBackground,
|
|
176
|
+
padding: '2px 6px',
|
|
177
|
+
borderRadius: '4px',
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
// Badges
|
|
181
|
+
'.badge': {
|
|
182
|
+
display: 'inline-flex',
|
|
183
|
+
alignItems: 'center',
|
|
184
|
+
gap: '4px',
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
'.badge img': {
|
|
188
|
+
height: '20px',
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
// Search input
|
|
192
|
+
'input[type="search"]': {
|
|
193
|
+
width: '100%',
|
|
194
|
+
padding: vars.spacing50,
|
|
195
|
+
border: `1px solid ${vars.codeBorder}`,
|
|
196
|
+
borderRadius: vars.borderRadius,
|
|
197
|
+
background: vars.background,
|
|
198
|
+
color: vars.textColor,
|
|
199
|
+
fontSize: 'inherit',
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
'input[type="search"]:focus': {
|
|
203
|
+
outline: 'none',
|
|
204
|
+
borderColor: vars.brandColor,
|
|
205
|
+
boxShadow: `0 0 0 2px rgba(99, 102, 241, 0.2)`,
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
// Markdown content styling
|
|
209
|
+
'.markdown-content': {
|
|
210
|
+
maxWidth: '48em',
|
|
211
|
+
margin: '0 auto',
|
|
212
|
+
padding: vars.spacing200,
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
'.markdown-content h1': {
|
|
216
|
+
fontSize: '2em',
|
|
217
|
+
marginTop: 0,
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
'.markdown-content h2': {
|
|
221
|
+
fontSize: '1.5em',
|
|
222
|
+
marginTop: '1.5em',
|
|
223
|
+
paddingBottom: '0.3em',
|
|
224
|
+
borderBottom: `1px solid ${vars.codeBorder}`,
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
'.markdown-content h3': {
|
|
228
|
+
fontSize: '1.25em',
|
|
229
|
+
marginTop: '1.25em',
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
// Table styles (global)
|
|
233
|
+
table: {
|
|
234
|
+
width: '100%',
|
|
235
|
+
borderCollapse: 'collapse',
|
|
236
|
+
marginBottom: '1em',
|
|
237
|
+
fontSize: '0.9em',
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
'th, td': {
|
|
241
|
+
padding: '6px 10px',
|
|
242
|
+
borderBottom: `1px solid ${vars.codeBorder}`,
|
|
243
|
+
textAlign: 'left',
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
th: {
|
|
247
|
+
fontWeight: 600,
|
|
248
|
+
background: 'rgba(0, 0, 0, 0.03)',
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
'.darkmode th': {
|
|
252
|
+
background: 'rgba(255, 255, 255, 0.03)',
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
'tr:nth-child(even)': {
|
|
256
|
+
background: 'rgba(0, 0, 0, 0.03)',
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
'.darkmode tr:nth-child(even)': {
|
|
260
|
+
background: 'rgba(255, 255, 255, 0.03)',
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
'tr:hover': {
|
|
264
|
+
background: 'rgba(0, 0, 0, 0.06)',
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
'.darkmode tr:hover': {
|
|
268
|
+
background: 'rgba(255, 255, 255, 0.06)',
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
// Loading state
|
|
272
|
+
'.loading': {
|
|
273
|
+
display: 'flex',
|
|
274
|
+
alignItems: 'center',
|
|
275
|
+
justifyContent: 'center',
|
|
276
|
+
height: '100%',
|
|
277
|
+
fontSize: '1.2em',
|
|
278
|
+
opacity: 0.6,
|
|
279
|
+
},
|
|
280
|
+
}
|