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,639 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* index.ts - Main entry point for agent-99 demo site
|
|
3
|
+
*
|
|
4
|
+
* Following the tosijs-ui documentation pattern:
|
|
5
|
+
* - Header with branding and settings
|
|
6
|
+
* - Sidebar navigation with search
|
|
7
|
+
* - Markdown content with live examples
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { elements, tosi, bindings, StyleSheet, bind } from 'tosijs'
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
icons,
|
|
14
|
+
sideNav,
|
|
15
|
+
SideNav,
|
|
16
|
+
sizeBreak,
|
|
17
|
+
popMenu,
|
|
18
|
+
markdownViewer,
|
|
19
|
+
} from 'tosijs-ui'
|
|
20
|
+
|
|
21
|
+
import { styleSpec } from './style'
|
|
22
|
+
StyleSheet('demo-style', styleSpec)
|
|
23
|
+
|
|
24
|
+
// Import playground components
|
|
25
|
+
import { playground, Playground } from './playground'
|
|
26
|
+
import { tjsPlayground, TJSPlayground } from './tjs-playground'
|
|
27
|
+
import { tsPlayground, TSPlayground } from './ts-playground'
|
|
28
|
+
|
|
29
|
+
// Import new demo navigation
|
|
30
|
+
import { demoNav, DemoNav, tjsExamples } from './demo-nav'
|
|
31
|
+
import { tsExamples } from './ts-examples'
|
|
32
|
+
|
|
33
|
+
// Import examples
|
|
34
|
+
import { examples as ajsExamples } from './examples'
|
|
35
|
+
|
|
36
|
+
// Import settings dialog
|
|
37
|
+
import { showSettingsDialog } from './settings'
|
|
38
|
+
|
|
39
|
+
// Import tjs-lang for live examples
|
|
40
|
+
import * as agent from '../../src'
|
|
41
|
+
import * as tosijs from 'tosijs'
|
|
42
|
+
import * as tosijsui from 'tosijs-ui'
|
|
43
|
+
|
|
44
|
+
// Import capabilities builder for live examples
|
|
45
|
+
import { buildCapabilities, getSettings } from './capabilities'
|
|
46
|
+
|
|
47
|
+
// Create a demo runtime that uses settings-based capabilities
|
|
48
|
+
const demoRuntime = {
|
|
49
|
+
// Wraps vm.run with capabilities from settings
|
|
50
|
+
async run(ast: any, args: any, options: any = {}) {
|
|
51
|
+
const vm = new agent.AgentVM()
|
|
52
|
+
const caps = buildCapabilities(getSettings())
|
|
53
|
+
return vm.run(ast, args, {
|
|
54
|
+
...options,
|
|
55
|
+
capabilities: {
|
|
56
|
+
...options.capabilities,
|
|
57
|
+
llm: caps.llm,
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Make available globally for debugging
|
|
64
|
+
Object.assign(window, { agent, tosijs, tosijsui, demoRuntime })
|
|
65
|
+
|
|
66
|
+
// Load documentation
|
|
67
|
+
import docs from '../docs.json'
|
|
68
|
+
|
|
69
|
+
// Add playgrounds as special pages
|
|
70
|
+
const ajsPlaygroundDoc = {
|
|
71
|
+
title: '▶ AJS Playground',
|
|
72
|
+
filename: 'playground',
|
|
73
|
+
text: '',
|
|
74
|
+
isPlayground: 'ajs',
|
|
75
|
+
pin: 'top',
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const tjsPlaygroundDoc = {
|
|
79
|
+
title: '▶ TJS Playground',
|
|
80
|
+
filename: 'tjs-playground',
|
|
81
|
+
text: '',
|
|
82
|
+
isPlayground: 'tjs',
|
|
83
|
+
pin: 'top',
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Insert playgrounds at top
|
|
87
|
+
const allDocs = [ajsPlaygroundDoc, tjsPlaygroundDoc, ...docs]
|
|
88
|
+
|
|
89
|
+
const PROJECT = 'tjs-lang'
|
|
90
|
+
const VERSION = '0.1.0' // TODO: import from package.json
|
|
91
|
+
|
|
92
|
+
// Determine initial doc from URL
|
|
93
|
+
const docName =
|
|
94
|
+
document.location.search !== ''
|
|
95
|
+
? document.location.search.substring(1).split('&')[0]
|
|
96
|
+
: 'README.md'
|
|
97
|
+
const currentDoc =
|
|
98
|
+
allDocs.find((doc: any) => doc.filename === docName) ||
|
|
99
|
+
allDocs.find((d: any) => d.filename === 'README.md') ||
|
|
100
|
+
allDocs[0]
|
|
101
|
+
|
|
102
|
+
// Initialize reactive state
|
|
103
|
+
const { app, prefs } = tosi({
|
|
104
|
+
app: {
|
|
105
|
+
title: PROJECT,
|
|
106
|
+
version: VERSION,
|
|
107
|
+
githubUrl: `https://github.com/tonioloewald/${PROJECT}#readme`,
|
|
108
|
+
npmUrl: `https://www.npmjs.com/package/tjs-lang`,
|
|
109
|
+
bundleBadgeUrl: `https://deno.bundlejs.com/?q=tjs-lang&badge=`,
|
|
110
|
+
bundleUrl: `https://bundlejs.com/?q=tjs-lang`,
|
|
111
|
+
docs: allDocs,
|
|
112
|
+
currentDoc,
|
|
113
|
+
compact: false,
|
|
114
|
+
currentView: 'home' as 'home' | 'ajs' | 'tjs' | 'ts',
|
|
115
|
+
currentExample: null as any,
|
|
116
|
+
},
|
|
117
|
+
prefs: {
|
|
118
|
+
// UI settings (stored in localStorage)
|
|
119
|
+
theme: localStorage.getItem('theme') || 'system',
|
|
120
|
+
highContrast: localStorage.getItem('highContrast') === 'true',
|
|
121
|
+
// LLM settings (stored in localStorage)
|
|
122
|
+
preferredProvider: localStorage.getItem('preferredProvider') || 'auto',
|
|
123
|
+
openaiKey: localStorage.getItem('openaiKey') || '',
|
|
124
|
+
anthropicKey: localStorage.getItem('anthropicKey') || '',
|
|
125
|
+
deepseekKey: localStorage.getItem('deepseekKey') || '',
|
|
126
|
+
customLlmUrl: localStorage.getItem('customLlmUrl') || '',
|
|
127
|
+
},
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
// Persist preferences
|
|
131
|
+
const savePrefs = () => {
|
|
132
|
+
// UI settings
|
|
133
|
+
localStorage.setItem('theme', prefs.theme.valueOf())
|
|
134
|
+
localStorage.setItem('highContrast', String(prefs.highContrast.valueOf()))
|
|
135
|
+
// LLM settings
|
|
136
|
+
localStorage.setItem('preferredProvider', prefs.preferredProvider.valueOf())
|
|
137
|
+
localStorage.setItem('openaiKey', prefs.openaiKey.valueOf())
|
|
138
|
+
localStorage.setItem('anthropicKey', prefs.anthropicKey.valueOf())
|
|
139
|
+
localStorage.setItem('deepseekKey', prefs.deepseekKey.valueOf())
|
|
140
|
+
localStorage.setItem('customLlmUrl', prefs.customLlmUrl.valueOf())
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Custom bindings
|
|
144
|
+
bindings.docLink = {
|
|
145
|
+
toDOM(elt: HTMLElement, filename: string) {
|
|
146
|
+
elt.setAttribute('href', `?${filename}`)
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
bindings.current = {
|
|
151
|
+
toDOM(elt: HTMLElement, currentFile: string) {
|
|
152
|
+
const boundFile = elt.getAttribute('href') || ''
|
|
153
|
+
elt.classList.toggle('current', currentFile === boundFile.substring(1))
|
|
154
|
+
},
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Elements
|
|
158
|
+
const { h1, h2, div, span, a, img, header, button, template, input } = elements
|
|
159
|
+
|
|
160
|
+
// Theme binding
|
|
161
|
+
bind(document.body, 'prefs.theme', {
|
|
162
|
+
toDOM(element: HTMLElement, theme: string) {
|
|
163
|
+
if (theme === 'system') {
|
|
164
|
+
theme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
165
|
+
? 'dark'
|
|
166
|
+
: 'light'
|
|
167
|
+
}
|
|
168
|
+
element.classList.toggle('darkmode', theme === 'dark')
|
|
169
|
+
},
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
bind(document.body, 'prefs.highContrast', {
|
|
173
|
+
toDOM(element: HTMLElement, highContrast: any) {
|
|
174
|
+
element.classList.toggle('high-contrast', highContrast.valueOf())
|
|
175
|
+
},
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
// Handle browser navigation
|
|
179
|
+
window.addEventListener('popstate', () => {
|
|
180
|
+
const filename = window.location.search.substring(1)
|
|
181
|
+
app.currentDoc =
|
|
182
|
+
app.docs.find((doc: any) => doc.filename === filename) || app.docs[0]
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
// URL state management for view and example
|
|
186
|
+
function loadViewStateFromURL() {
|
|
187
|
+
const hash = window.location.hash.slice(1)
|
|
188
|
+
if (!hash) {
|
|
189
|
+
app.currentView = 'home'
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const params = new URLSearchParams(hash)
|
|
194
|
+
const view = params.get('view')
|
|
195
|
+
const example = params.get('example')
|
|
196
|
+
|
|
197
|
+
if (view === 'home') {
|
|
198
|
+
app.currentView = 'home'
|
|
199
|
+
app.currentExample = null
|
|
200
|
+
} else if (view === 'ajs' || view === 'tjs' || view === 'ts') {
|
|
201
|
+
app.currentView = view
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (example) {
|
|
205
|
+
// Find example by name in appropriate list
|
|
206
|
+
if (view === 'ts') {
|
|
207
|
+
const found = tsExamples.find((e: any) => e.name === example)
|
|
208
|
+
if (found) app.currentExample = found
|
|
209
|
+
} else if (view === 'tjs') {
|
|
210
|
+
const found = tjsExamples.find((e: any) => e.name === example)
|
|
211
|
+
if (found) app.currentExample = found
|
|
212
|
+
} else {
|
|
213
|
+
const found = ajsExamples.find((e: any) => e.name === example)
|
|
214
|
+
if (found) app.currentExample = found
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function saveViewStateToURL(view: string, exampleName?: string) {
|
|
220
|
+
const params = new URLSearchParams(window.location.hash.slice(1))
|
|
221
|
+
params.set('view', view)
|
|
222
|
+
if (exampleName) {
|
|
223
|
+
params.set('example', exampleName)
|
|
224
|
+
} else {
|
|
225
|
+
params.delete('example')
|
|
226
|
+
}
|
|
227
|
+
const newHash = params.toString()
|
|
228
|
+
window.history.replaceState(null, '', `#${newHash}`)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Load initial state from URL
|
|
232
|
+
loadViewStateFromURL()
|
|
233
|
+
|
|
234
|
+
// Listen for hash changes
|
|
235
|
+
window.addEventListener('hashchange', loadViewStateFromURL)
|
|
236
|
+
|
|
237
|
+
// Main app
|
|
238
|
+
const main = document.querySelector('main') as HTMLElement
|
|
239
|
+
|
|
240
|
+
if (main) {
|
|
241
|
+
// Clear loading state
|
|
242
|
+
main.innerHTML = ''
|
|
243
|
+
|
|
244
|
+
main.append(
|
|
245
|
+
// Header
|
|
246
|
+
header(
|
|
247
|
+
// Menu toggle (compact mode)
|
|
248
|
+
button(
|
|
249
|
+
{
|
|
250
|
+
class: 'iconic',
|
|
251
|
+
title: 'Toggle navigation',
|
|
252
|
+
bind: {
|
|
253
|
+
value: app.compact,
|
|
254
|
+
binding: {
|
|
255
|
+
toDOM(element: HTMLElement, compact: boolean) {
|
|
256
|
+
element.style.display = compact ? '' : 'none'
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
onClick() {
|
|
261
|
+
const nav = document.querySelector(SideNav.tagName!) as SideNav
|
|
262
|
+
nav.contentVisible = !nav.contentVisible
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
icons.menu()
|
|
266
|
+
),
|
|
267
|
+
|
|
268
|
+
// Logo and title
|
|
269
|
+
a(
|
|
270
|
+
{
|
|
271
|
+
href: '/',
|
|
272
|
+
style: {
|
|
273
|
+
display: 'flex',
|
|
274
|
+
alignItems: 'center',
|
|
275
|
+
gap: '8px',
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
// Agent icon
|
|
279
|
+
img({ src: '/favicon.svg', style: { width: '32px', height: '32px' } }),
|
|
280
|
+
h1('tjs-lang')
|
|
281
|
+
),
|
|
282
|
+
|
|
283
|
+
// Elastic spacer
|
|
284
|
+
span({ class: 'elastic' }),
|
|
285
|
+
|
|
286
|
+
// Bundle size badge (responsive)
|
|
287
|
+
sizeBreak(
|
|
288
|
+
{ minWidth: 600 },
|
|
289
|
+
span(
|
|
290
|
+
{ class: 'badge' },
|
|
291
|
+
a(
|
|
292
|
+
{ href: app.bundleUrl, target: '_blank' },
|
|
293
|
+
img({ alt: 'bundle size', src: app.bundleBadgeUrl })
|
|
294
|
+
)
|
|
295
|
+
),
|
|
296
|
+
span({ slot: 'small' })
|
|
297
|
+
),
|
|
298
|
+
|
|
299
|
+
// GitHub link
|
|
300
|
+
a(
|
|
301
|
+
{
|
|
302
|
+
class: 'iconic',
|
|
303
|
+
title: 'GitHub',
|
|
304
|
+
target: '_blank',
|
|
305
|
+
href: app.githubUrl,
|
|
306
|
+
},
|
|
307
|
+
icons.github()
|
|
308
|
+
),
|
|
309
|
+
|
|
310
|
+
// NPM link
|
|
311
|
+
a(
|
|
312
|
+
{
|
|
313
|
+
class: 'iconic',
|
|
314
|
+
title: 'npm',
|
|
315
|
+
target: '_blank',
|
|
316
|
+
href: app.npmUrl,
|
|
317
|
+
},
|
|
318
|
+
icons.npm()
|
|
319
|
+
),
|
|
320
|
+
|
|
321
|
+
// Settings menu
|
|
322
|
+
button(
|
|
323
|
+
{
|
|
324
|
+
class: 'iconic',
|
|
325
|
+
title: 'Settings',
|
|
326
|
+
onClick(event: MouseEvent) {
|
|
327
|
+
popMenu({
|
|
328
|
+
target: event.target as HTMLButtonElement,
|
|
329
|
+
menuItems: [
|
|
330
|
+
{
|
|
331
|
+
caption: 'API Keys',
|
|
332
|
+
icon: 'key',
|
|
333
|
+
action: () => {
|
|
334
|
+
showSettingsDialog(
|
|
335
|
+
{
|
|
336
|
+
preferredProvider:
|
|
337
|
+
prefs.preferredProvider.valueOf() as any,
|
|
338
|
+
openaiKey: prefs.openaiKey.valueOf(),
|
|
339
|
+
anthropicKey: prefs.anthropicKey.valueOf(),
|
|
340
|
+
deepseekKey: prefs.deepseekKey.valueOf(),
|
|
341
|
+
customLlmUrl: prefs.customLlmUrl.valueOf(),
|
|
342
|
+
},
|
|
343
|
+
(settings) => {
|
|
344
|
+
prefs.preferredProvider = settings.preferredProvider
|
|
345
|
+
prefs.openaiKey = settings.openaiKey
|
|
346
|
+
prefs.anthropicKey = settings.anthropicKey
|
|
347
|
+
prefs.deepseekKey = settings.deepseekKey
|
|
348
|
+
prefs.customLlmUrl = settings.customLlmUrl
|
|
349
|
+
savePrefs()
|
|
350
|
+
}
|
|
351
|
+
)
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
caption: 'Color Theme',
|
|
356
|
+
icon: 'rgb',
|
|
357
|
+
menuItems: [
|
|
358
|
+
{
|
|
359
|
+
caption: 'System',
|
|
360
|
+
checked: () => prefs.theme.valueOf() === 'system',
|
|
361
|
+
action: () => {
|
|
362
|
+
prefs.theme = 'system'
|
|
363
|
+
savePrefs()
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
caption: 'Dark',
|
|
368
|
+
checked: () => prefs.theme.valueOf() === 'dark',
|
|
369
|
+
action: () => {
|
|
370
|
+
prefs.theme = 'dark'
|
|
371
|
+
savePrefs()
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
caption: 'Light',
|
|
376
|
+
checked: () => prefs.theme.valueOf() === 'light',
|
|
377
|
+
action: () => {
|
|
378
|
+
prefs.theme = 'light'
|
|
379
|
+
savePrefs()
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
null,
|
|
383
|
+
{
|
|
384
|
+
caption: 'High Contrast',
|
|
385
|
+
checked: () => prefs.highContrast.valueOf(),
|
|
386
|
+
action: () => {
|
|
387
|
+
prefs.highContrast = !prefs.highContrast.valueOf()
|
|
388
|
+
savePrefs()
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
],
|
|
392
|
+
},
|
|
393
|
+
null,
|
|
394
|
+
{
|
|
395
|
+
caption: 'GitHub',
|
|
396
|
+
icon: 'github',
|
|
397
|
+
action: () => window.open(app.githubUrl.valueOf(), '_blank'),
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
caption: 'npm',
|
|
401
|
+
icon: 'npm',
|
|
402
|
+
action: () => window.open(app.npmUrl.valueOf(), '_blank'),
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
})
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
icons.moreVertical()
|
|
409
|
+
)
|
|
410
|
+
),
|
|
411
|
+
|
|
412
|
+
// Side navigation + content
|
|
413
|
+
sideNav(
|
|
414
|
+
{
|
|
415
|
+
name: 'Examples',
|
|
416
|
+
navSize: 220,
|
|
417
|
+
minSize: 600,
|
|
418
|
+
style: {
|
|
419
|
+
flex: '1 1 auto',
|
|
420
|
+
overflow: 'hidden',
|
|
421
|
+
},
|
|
422
|
+
onChange() {
|
|
423
|
+
const nav = document.querySelector(SideNav.tagName!) as SideNav
|
|
424
|
+
app.compact = nav.compact
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
// Demo navigation with 4 accordion sections
|
|
429
|
+
(() => {
|
|
430
|
+
const nav = demoNav({
|
|
431
|
+
slot: 'nav',
|
|
432
|
+
style: {
|
|
433
|
+
width: '100%',
|
|
434
|
+
height: '100%',
|
|
435
|
+
},
|
|
436
|
+
}) as DemoNav
|
|
437
|
+
|
|
438
|
+
// Pass docs to the nav component
|
|
439
|
+
nav.docs = docs
|
|
440
|
+
|
|
441
|
+
// Handle AJS example selection - load into AJS playground
|
|
442
|
+
nav.addEventListener('select-ajs-example', ((event: CustomEvent) => {
|
|
443
|
+
const { example } = event.detail
|
|
444
|
+
app.currentView = 'ajs'
|
|
445
|
+
app.currentExample = example
|
|
446
|
+
saveViewStateToURL('ajs', example.name)
|
|
447
|
+
}) as EventListener)
|
|
448
|
+
|
|
449
|
+
// Handle TJS example selection - load into TJS playground
|
|
450
|
+
nav.addEventListener('select-tjs-example', ((event: CustomEvent) => {
|
|
451
|
+
const { example } = event.detail
|
|
452
|
+
app.currentView = 'tjs'
|
|
453
|
+
app.currentExample = example
|
|
454
|
+
saveViewStateToURL('tjs', example.name)
|
|
455
|
+
}) as EventListener)
|
|
456
|
+
|
|
457
|
+
// Handle TS example selection - load into TS playground
|
|
458
|
+
nav.addEventListener('select-ts-example', ((event: CustomEvent) => {
|
|
459
|
+
const { example } = event.detail
|
|
460
|
+
app.currentView = 'ts'
|
|
461
|
+
app.currentExample = example
|
|
462
|
+
saveViewStateToURL('ts', example.name)
|
|
463
|
+
}) as EventListener)
|
|
464
|
+
|
|
465
|
+
// Handle Home selection - show README
|
|
466
|
+
nav.addEventListener('select-home', (() => {
|
|
467
|
+
app.currentView = 'home'
|
|
468
|
+
app.currentExample = null
|
|
469
|
+
saveViewStateToURL('home')
|
|
470
|
+
}) as EventListener)
|
|
471
|
+
|
|
472
|
+
// Nav syncs its own state from URL - no need to overwrite on initial load
|
|
473
|
+
|
|
474
|
+
return nav
|
|
475
|
+
})(),
|
|
476
|
+
|
|
477
|
+
// Content area - shows the active playground
|
|
478
|
+
div(
|
|
479
|
+
{
|
|
480
|
+
style: {
|
|
481
|
+
position: 'relative',
|
|
482
|
+
overflow: 'hidden',
|
|
483
|
+
height: '100%',
|
|
484
|
+
display: 'flex',
|
|
485
|
+
flexDirection: 'column',
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
// Home/README view
|
|
489
|
+
(() => {
|
|
490
|
+
const readmeDoc = docs.find((d: any) => d.filename === 'README.md')
|
|
491
|
+
const viewer = markdownViewer({
|
|
492
|
+
value: readmeDoc?.text || '# Welcome to tjs-lang',
|
|
493
|
+
style: {
|
|
494
|
+
display: 'none',
|
|
495
|
+
flex: '1 1 auto',
|
|
496
|
+
height: '100%',
|
|
497
|
+
padding: '20px 40px',
|
|
498
|
+
overflow: 'auto',
|
|
499
|
+
maxWidth: '900px',
|
|
500
|
+
},
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
// Show/hide based on currentView
|
|
504
|
+
bind(viewer, 'app.currentView', {
|
|
505
|
+
toDOM(element: HTMLElement, view: string) {
|
|
506
|
+
element.style.display = view === 'home' ? 'block' : 'none'
|
|
507
|
+
},
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
return viewer
|
|
511
|
+
})(),
|
|
512
|
+
|
|
513
|
+
// AJS Playground
|
|
514
|
+
(() => {
|
|
515
|
+
const pg = playground({
|
|
516
|
+
style: {
|
|
517
|
+
display: 'none',
|
|
518
|
+
flex: '1 1 auto',
|
|
519
|
+
height: '100%',
|
|
520
|
+
padding: '10px',
|
|
521
|
+
},
|
|
522
|
+
}) as Playground
|
|
523
|
+
|
|
524
|
+
// Show/hide based on currentView
|
|
525
|
+
bind(pg, 'app.currentView', {
|
|
526
|
+
toDOM(element: HTMLElement, view: string) {
|
|
527
|
+
element.style.display = view === 'ajs' ? 'block' : 'none'
|
|
528
|
+
},
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
// Load example when selected
|
|
532
|
+
bind(pg, 'app.currentExample', {
|
|
533
|
+
toDOM(element: Playground, example: any) {
|
|
534
|
+
if (
|
|
535
|
+
example &&
|
|
536
|
+
app.currentView.valueOf() === 'ajs' &&
|
|
537
|
+
element.editor
|
|
538
|
+
) {
|
|
539
|
+
element.editor.dispatch({
|
|
540
|
+
changes: {
|
|
541
|
+
from: 0,
|
|
542
|
+
to: element.editor.state.doc.length,
|
|
543
|
+
insert: example.code,
|
|
544
|
+
},
|
|
545
|
+
})
|
|
546
|
+
}
|
|
547
|
+
},
|
|
548
|
+
})
|
|
549
|
+
|
|
550
|
+
return pg
|
|
551
|
+
})(),
|
|
552
|
+
|
|
553
|
+
// TJS Playground
|
|
554
|
+
(() => {
|
|
555
|
+
const pg = tjsPlayground({
|
|
556
|
+
style: {
|
|
557
|
+
display: 'none',
|
|
558
|
+
flex: '1 1 auto',
|
|
559
|
+
height: '100%',
|
|
560
|
+
padding: '10px',
|
|
561
|
+
},
|
|
562
|
+
}) as TJSPlayground
|
|
563
|
+
|
|
564
|
+
// Show/hide based on currentView
|
|
565
|
+
bind(pg, 'app.currentView', {
|
|
566
|
+
toDOM(element: HTMLElement, view: string) {
|
|
567
|
+
// Use 'flex' not 'block' - component has flex layout internally
|
|
568
|
+
element.style.display = view === 'tjs' ? 'flex' : 'none'
|
|
569
|
+
},
|
|
570
|
+
})
|
|
571
|
+
|
|
572
|
+
// Load example when selected (auto-runs via setSource)
|
|
573
|
+
bind(pg, 'app.currentExample', {
|
|
574
|
+
toDOM(element: TJSPlayground, example: any) {
|
|
575
|
+
if (example && app.currentView.valueOf() === 'tjs') {
|
|
576
|
+
setTimeout(() => {
|
|
577
|
+
if (element.setSource) {
|
|
578
|
+
const code =
|
|
579
|
+
typeof example.code === 'string'
|
|
580
|
+
? example.code
|
|
581
|
+
: String(example.code)
|
|
582
|
+
element.setSource(code, example.name)
|
|
583
|
+
}
|
|
584
|
+
}, 0)
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
})
|
|
588
|
+
|
|
589
|
+
return pg
|
|
590
|
+
})(),
|
|
591
|
+
|
|
592
|
+
// TS Playground (TypeScript -> TJS -> JS pipeline)
|
|
593
|
+
(() => {
|
|
594
|
+
const pg = tsPlayground({
|
|
595
|
+
style: {
|
|
596
|
+
display: 'none',
|
|
597
|
+
flex: '1 1 auto',
|
|
598
|
+
height: '100%',
|
|
599
|
+
padding: '10px',
|
|
600
|
+
},
|
|
601
|
+
}) as TSPlayground
|
|
602
|
+
|
|
603
|
+
// Show/hide based on currentView
|
|
604
|
+
bind(pg, 'app.currentView', {
|
|
605
|
+
toDOM(element: HTMLElement, view: string) {
|
|
606
|
+
element.style.display = view === 'ts' ? 'flex' : 'none'
|
|
607
|
+
},
|
|
608
|
+
})
|
|
609
|
+
|
|
610
|
+
// Load example when selected
|
|
611
|
+
bind(pg, 'app.currentExample', {
|
|
612
|
+
toDOM(element: TSPlayground, example: any) {
|
|
613
|
+
if (example && app.currentView.valueOf() === 'ts') {
|
|
614
|
+
setTimeout(() => {
|
|
615
|
+
if (element.setSource) {
|
|
616
|
+
const code =
|
|
617
|
+
typeof example.code === 'string'
|
|
618
|
+
? example.code
|
|
619
|
+
: String(example.code)
|
|
620
|
+
element.setSource(code, example.name)
|
|
621
|
+
}
|
|
622
|
+
}, 0)
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
})
|
|
626
|
+
|
|
627
|
+
return pg
|
|
628
|
+
})()
|
|
629
|
+
)
|
|
630
|
+
)
|
|
631
|
+
)
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Log welcome message
|
|
635
|
+
console.log(
|
|
636
|
+
`%c tjs-lang %c v${VERSION} `,
|
|
637
|
+
'background: #6366f1; color: white; padding: 2px 6px; border-radius: 3px 0 0 3px;',
|
|
638
|
+
'background: #374151; color: white; padding: 2px 6px; border-radius: 0 3px 3px 0;'
|
|
639
|
+
)
|