@junojs/core 0.1.2 → 0.1.4

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,2483 @@
1
+ <div
2
+ class="bg-white text-gray-700 dark:bg-[#0a0a0a] dark:text-slate-300 font-sans min-h-screen"
3
+ >
4
+ <!-- Fixed Left Sidebar -->
5
+ <aside
6
+ class="fixed top-0 left-0 h-screen w-60 border-r border-gray-200 dark:border-slate-800/60 flex flex-col bg-white dark:bg-[#0a0a0a] overflow-y-auto"
7
+ style="z-index: 40"
8
+ >
9
+ <div
10
+ class="h-14 flex items-center px-5 border-b border-gray-200 dark:border-slate-800/60 flex-shrink-0"
11
+ >
12
+ <div class="flex items-center gap-2 flex-1">
13
+ <div
14
+ class="w-6 h-6 rounded bg-blue-500 flex items-center justify-center text-[9px] font-black text-white"
15
+ >
16
+ NF
17
+ </div>
18
+ <span class="font-semibold text-gray-900 dark:text-white text-sm"
19
+ >JunoJS</span
20
+ >
21
+ <span
22
+ class="text-[10px] font-bold text-blue-400 bg-blue-500/10 px-1.5 py-0.5 rounded border border-blue-500/20"
23
+ >v1.0</span
24
+ >
25
+ </div>
26
+ </div>
27
+ <nav class="flex-1 px-3 py-5 space-y-6">
28
+ <div class="space-y-0.5">
29
+ <p
30
+ class="px-3 py-1 text-[10.5px] font-semibold text-gray-400 dark:text-slate-500 uppercase tracking-widest"
31
+ >
32
+ Getting Started
33
+ </p>
34
+ <button
35
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'introduction' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
36
+ @click="selectTab('introduction')"
37
+ >
38
+ Introduction
39
+ </button>
40
+ <button
41
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'installation' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
42
+ @click="selectTab('installation')"
43
+ >
44
+ Installation
45
+ </button>
46
+ <button
47
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'structure' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
48
+ @click="selectTab('structure')"
49
+ >
50
+ Project Structure
51
+ </button>
52
+ <button
53
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'aidev' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
54
+ @click="selectTab('aidev')"
55
+ >
56
+ AI Development
57
+ </button>
58
+ <button
59
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'quickstart' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
60
+ @click="selectTab('quickstart')"
61
+ >
62
+ Quick Start
63
+ </button>
64
+ </div>
65
+ <div class="space-y-0.5">
66
+ <p
67
+ class="px-3 py-1 text-[10.5px] font-semibold text-gray-400 dark:text-slate-500 uppercase tracking-widest"
68
+ >
69
+ Core Concepts
70
+ </p>
71
+ <button
72
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'reactivity' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
73
+ @click="selectTab('reactivity')"
74
+ >
75
+ Reactivity
76
+ </button>
77
+ <button
78
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'templates' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
79
+ @click="selectTab('templates')"
80
+ >
81
+ Template Syntax
82
+ </button>
83
+ <button
84
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'lifecycle' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
85
+ @click="selectTab('lifecycle')"
86
+ >
87
+ Lifecycle Hooks
88
+ </button>
89
+ </div>
90
+ <div class="space-y-0.5">
91
+ <p
92
+ class="px-3 py-1 text-[10.5px] font-semibold text-gray-400 dark:text-slate-500 uppercase tracking-widest"
93
+ >
94
+ Common Services
95
+ </p>
96
+ <button
97
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'http' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
98
+ @click="selectTab('http')"
99
+ >
100
+ HTTP Client
101
+ </button>
102
+ <button
103
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'i18n' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
104
+ @click="selectTab('i18n')"
105
+ >
106
+ Internationalization
107
+ </button>
108
+ <button
109
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'forms' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
110
+ @click="selectTab('forms')"
111
+ >
112
+ Forms &amp; Validation
113
+ </button>
114
+ <button
115
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'routing' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
116
+ @click="selectTab('routing')"
117
+ >
118
+ Router Service
119
+ </button>
120
+ </div>
121
+ <div class="space-y-0.5">
122
+ <p
123
+ class="px-3 py-1 text-[10.5px] font-semibold text-gray-400 dark:text-slate-500 uppercase tracking-widest"
124
+ >
125
+ API Reference
126
+ </p>
127
+ <button
128
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'decorators' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
129
+ @click="selectTab('decorators')"
130
+ >
131
+ Decorators
132
+ </button>
133
+ <button
134
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'engine' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
135
+ @click="selectTab('engine')"
136
+ >
137
+ Engine API
138
+ </button>
139
+ </div>
140
+ <div class="space-y-0.5">
141
+ <p
142
+ class="px-3 py-1 text-[10.5px] font-semibold text-gray-400 dark:text-slate-500 uppercase tracking-widest"
143
+ >
144
+ Resources
145
+ </p>
146
+ <button
147
+ class="w-full text-left px-3 py-[7px] rounded-md text-sm transition-colors {activeTab === 'samples' ? 'bg-gray-100 text-gray-900 font-medium dark:bg-slate-800/70 dark:text-white' : 'text-gray-500 hover:text-gray-900 hover:bg-gray-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/30'}"
148
+ @click="selectTab('samples')"
149
+ >
150
+ Samples
151
+ </button>
152
+ </div>
153
+ </nav>
154
+ </aside>
155
+
156
+ <!-- Main wrapper offset by sidebar -->
157
+ <div class="ml-60">
158
+ <!-- Sticky top header -->
159
+ <header
160
+ class="sticky top-0 h-14 flex items-center justify-between px-8 border-b border-gray-100 dark:border-slate-800/40 bg-white/70 dark:bg-[#0a0a0a]/70 backdrop-blur-md"
161
+ style="z-index: 30"
162
+ >
163
+ <!-- Left: Breadcrumbs -->
164
+ <div class="flex items-center gap-2.5 text-[13px] tracking-tight">
165
+ <div class="flex items-center gap-2 group cursor-default">
166
+ <span
167
+ class="text-gray-400 dark:text-slate-500 group-hover:text-gray-600 dark:group-hover:text-slate-300 transition-colors"
168
+ >{activeSectionName}</span
169
+ >
170
+ <span class="text-gray-300 dark:text-slate-800 font-light select-none"
171
+ >/</span
172
+ >
173
+ <span class="text-gray-900 dark:text-white font-semibold"
174
+ >{activePageName}</span
175
+ >
176
+ </div>
177
+ </div>
178
+
179
+ <!-- Center: Search Mockup -->
180
+ <div class="hidden md:flex flex-1 max-w-md mx-12">
181
+ <div class="w-full relative group">
182
+ <span
183
+ class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 dark:text-slate-600 text-lg group-focus-within:text-blue-500 transition-colors"
184
+ >search</span
185
+ >
186
+ <input
187
+ type="text"
188
+ placeholder="Search documentation..."
189
+ class="w-full h-9 pl-10 pr-4 bg-gray-100/50 dark:bg-slate-900/50 border border-gray-200/50 dark:border-slate-800/50 rounded-full text-sm text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-slate-600 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500/50 transition-all"
190
+ />
191
+ <div
192
+ class="absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-1 opacity-40 group-focus-within:opacity-0 transition-opacity"
193
+ >
194
+ <kbd
195
+ class="px-1.5 py-0.5 rounded border border-gray-300 dark:border-slate-700 bg-white dark:bg-slate-800 text-[10px] font-sans"
196
+ >⌘</kbd
197
+ >
198
+ <kbd
199
+ class="px-1.5 py-0.5 rounded border border-gray-300 dark:border-slate-700 bg-white dark:bg-slate-800 text-[10px] font-sans"
200
+ >K</kbd
201
+ >
202
+ </div>
203
+ </div>
204
+ </div>
205
+
206
+ <!-- Right: Actions & Theme -->
207
+ <div class="flex items-center gap-1.5">
208
+ <a
209
+ href="https://github.com"
210
+ target="_blank"
211
+ class="p-2 text-gray-500 hover:text-gray-900 dark:text-slate-400 dark:hover:text-white transition-colors"
212
+ >
213
+ <svg viewBox="0 0 24 24" class="w-5 h-5 fill-current">
214
+ <path
215
+ d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
216
+ />
217
+ </svg>
218
+ </a>
219
+ <div class="w-px h-4 bg-gray-200 dark:bg-slate-800 mx-1"></div>
220
+ <button
221
+ @click="toggleTheme"
222
+ class="w-9 h-9 flex items-center justify-center rounded-lg text-gray-500 hover:bg-gray-100 dark:text-slate-400 dark:hover:bg-slate-800/60 transition-all"
223
+ >
224
+ <if condition="{darkMode === 'dark'}">
225
+ <span class="material-symbols-outlined text-[20px]"
226
+ >light_mode</span
227
+ >
228
+ <else>
229
+ <span class="material-symbols-outlined text-[20px]"
230
+ >dark_mode</span
231
+ >
232
+ </else>
233
+ </if>
234
+ </button>
235
+ </div>
236
+ </header>
237
+
238
+ <!-- Content + Right ToC -->
239
+ <div class="flex">
240
+ <!-- Page Content -->
241
+ <main class="flex-1 min-w-0">
242
+ <div class="max-w-2xl px-10 pt-14 pb-28 mx-auto">
243
+ <!-- ── INTRODUCTION ── -->
244
+ <if condition="{activeTab === 'introduction'}">
245
+ <article class="space-y-8">
246
+ <div>
247
+ <p
248
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
249
+ >
250
+ Getting Started
251
+ </p>
252
+ <h1
253
+ id="overview"
254
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
255
+ >
256
+ Introduction
257
+ </h1>
258
+ <p
259
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
260
+ >
261
+ JunoJS is an AI-native reactive framework built on native
262
+ Web Components. It delivers sub-millisecond DOM updates
263
+ through a Proxy-based reactivity system, without a Virtual DOM
264
+ or build-time compilation.
265
+ </p>
266
+ </div>
267
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
268
+ <div>
269
+ <h2
270
+ id="features"
271
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
272
+ >
273
+ Key Features
274
+ </h2>
275
+ <ul class="space-y-3 text-sm text-slate-400 leading-7">
276
+ <li class="flex gap-3">
277
+ <span class="text-blue-500 mt-0.5">▸</span
278
+ ><span
279
+ ><strong class="text-gray-900 dark:text-slate-200"
280
+ >Web Components</strong
281
+ >
282
+ — Standards-based custom elements that work in any
283
+ environment, no framework lock-in.</span
284
+ >
285
+ </li>
286
+ <li class="flex gap-3">
287
+ <span class="text-blue-500 mt-0.5">▸</span
288
+ ><span
289
+ ><strong class="text-gray-900 dark:text-slate-200"
290
+ >Proxy Reactivity</strong
291
+ >
292
+ — Atomic state management. Mutate a property and the DOM
293
+ reconciles itself instantly.</span
294
+ >
295
+ </li>
296
+ <li class="flex gap-3">
297
+ <span class="text-blue-500 mt-0.5">▸</span
298
+ ><span
299
+ ><strong class="text-gray-900 dark:text-slate-200"
300
+ >HTML Templates</strong
301
+ >
302
+ — Structural logic via semantic tags:
303
+ <code
304
+ class="bg-slate-900 text-blue-400 px-1 rounded text-xs"
305
+ >&lt;if&gt;</code
306
+ >,
307
+ <code
308
+ class="bg-slate-900 text-blue-400 px-1 rounded text-xs"
309
+ >&lt;for&gt;</code
310
+ >,
311
+ <code
312
+ class="bg-slate-900 text-blue-400 px-1 rounded text-xs"
313
+ >&lt;else&gt;</code
314
+ >.</span
315
+ >
316
+ </li>
317
+ <li class="flex gap-3">
318
+ <span class="text-blue-500 mt-0.5">▸</span
319
+ ><span
320
+ ><strong class="text-gray-900 dark:text-slate-200"
321
+ >Common Services</strong
322
+ >
323
+ — Built-in HTTP client, i18n, and form validation —
324
+ batteries included.</span
325
+ >
326
+ </li>
327
+ <li class="flex gap-3">
328
+ <span class="text-blue-500 mt-0.5">▸</span
329
+ ><span
330
+ ><strong class="text-gray-900 dark:text-slate-200"
331
+ >TypeScript-first</strong
332
+ >
333
+ — Decorator-driven component authoring with full type
334
+ safety.</span
335
+ >
336
+ </li>
337
+ </ul>
338
+ </div>
339
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
340
+ <div>
341
+ <h2
342
+ id="architecture"
343
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
344
+ >
345
+ Architecture
346
+ </h2>
347
+ <p class="text-sm text-gray-600 dark:text-slate-400 leading-7">
348
+ JunoJS consists of two layers. The
349
+ <strong class="text-gray-800 dark:text-slate-200"
350
+ >core engine</strong
351
+ >
352
+ handles reactivity, bootstrapping, and DOM reconciliation. The
353
+ <strong class="text-gray-800 dark:text-slate-200"
354
+ >common services</strong
355
+ >
356
+ layer provides HTTP, i18n, and form utilities. Components
357
+ bridge these layers via TypeScript decorators.
358
+ </p>
359
+ </div>
360
+ </article>
361
+ </if>
362
+
363
+ <!-- ── INSTALLATION ── -->
364
+ <if condition="{activeTab === 'installation'}">
365
+ <article class="space-y-8">
366
+ <div>
367
+ <p
368
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
369
+ >
370
+ Getting Started
371
+ </p>
372
+ <h1
373
+ id="install"
374
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
375
+ >
376
+ Installation
377
+ </h1>
378
+ <p
379
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
380
+ >
381
+ Install JunoJS via npm and configure TypeScript to support
382
+ the decorator metadata required by the framework.
383
+ </p>
384
+ </div>
385
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
386
+ <div>
387
+ <h2
388
+ id="npm"
389
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
390
+ >
391
+ Install the Package
392
+ </h2>
393
+ <pre
394
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
395
+ >
396
+ npm install @junojs/core reflect-metadata</pre
397
+ >
398
+ </div>
399
+ <div>
400
+ <h2
401
+ id="tsconfig"
402
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
403
+ >
404
+ TypeScript Configuration
405
+ </h2>
406
+ <p
407
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
408
+ >
409
+ Enable decorator metadata in your
410
+ <code
411
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs font-mono"
412
+ >tsconfig.json</code
413
+ >:
414
+ </p>
415
+ <pre
416
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
417
+ >
418
+ &#123;
419
+ "compilerOptions": &#123;
420
+ "experimentalDecorators": true,
421
+ "emitDecoratorMetadata": true,
422
+ "target": "ES2020",
423
+ "module": "ESNext"
424
+ &#125;
425
+ &#125;</pre
426
+ >
427
+ </div>
428
+ <div>
429
+ <h2
430
+ id="entry"
431
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
432
+ >
433
+ Entry Point
434
+ </h2>
435
+ <p
436
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
437
+ >
438
+ Import
439
+ <code
440
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs font-mono"
441
+ >reflect-metadata</code
442
+ >
443
+ once at the top of your application entry file — before any
444
+ decorators run.
445
+ </p>
446
+ <pre
447
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
448
+ >
449
+ import 'reflect-metadata';
450
+ import &#123; bootstrap &#125; from '@junojs/core';
451
+ import &#123; AppRoot &#125; from './app.component';
452
+
453
+ bootstrap(AppRoot);</pre
454
+ >
455
+ </div>
456
+ </article>
457
+ </if>
458
+ <!-- ── PROJECT STRUCTURE ── -->
459
+ <if condition="{activeTab === 'structure'}">
460
+ <article class="space-y-8">
461
+ <div>
462
+ <p
463
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
464
+ >
465
+ Getting Started
466
+ </p>
467
+ <h1
468
+ id="structure"
469
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
470
+ >
471
+ Project Structure
472
+ </h1>
473
+ <p
474
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
475
+ >
476
+ Master the architectural blueprint of JunoJS. Learn how to
477
+ organize your components, services, and pages to build
478
+ scalable, high-performance reactive applications.
479
+ </p>
480
+ </div>
481
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
482
+ <div>
483
+ <h2
484
+ id="app-structure"
485
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
486
+ >
487
+ Folder Structure
488
+ </h2>
489
+ <p class="text-sm text-gray-600 dark:text-slate-400 mb-4">
490
+ JunoJS follows a component-driven architecture where your
491
+ application is composed of modular elements organized into
492
+ pages and reusable components.
493
+ </p>
494
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60 mb-6"></div>
495
+ <div class="relative group">
496
+ <pre
497
+ class="bg-gray-50 dark:bg-slate-900/50 border border-gray-200 dark:border-slate-800 rounded-xl p-6 font-mono text-[13px] text-gray-700 dark:text-slate-300 overflow-x-auto leading-relaxed shadow-inner"
498
+ ><span class="text-emerald-500 font-bold">my-app/</span>
499
+ ├── <span class="text-emerald-400">src/</span>
500
+ │ ├── <span class="text-emerald-300">components/</span> <span class="text-gray-400"># Atomic UI components (Navbar, Card)</span>
501
+ │ │ └── footer/ <span class="text-gray-500">// Individual component folder</span>
502
+ │ │ ├── footer.ts
503
+ │ │ └── footer.css
504
+ │ ├── <span class="text-emerald-300">pages/</span> <span class="text-gray-400"># Routing-level view components (Home)</span>
505
+ │ │ ├── home/ <span class="text-gray-500">// Views linked to specific routes</span>
506
+ │ │ └── cart/
507
+ │ ├── <span class="text-emerald-300">services/</span> <span class="text-gray-400"># Singleton services (Store, API)</span>
508
+ │ ├── <span class="text-emerald-300">assets/</span> <span class="text-gray-400"># Images, global styles, and fonts</span>
509
+ │ ├── <span class="text-emerald-300 font-medium">main.ts</span> <span class="text-gray-500">// Application bootstrap & global config</span>
510
+ │ └── <span class="text-emerald-300 font-medium">app.component.ts</span> <span class="text-gray-500">// Root layout and shell</span>
511
+ ├── <span class="text-emerald-400 font-medium">templates/</span> <span class="text-gray-400"># HTML templates for custom elements</span>
512
+ ├── index.html <span class="text-gray-500">// Host document</span>
513
+ └── tsconfig.json <span class="text-gray-500">// Decorator & metadata configuration</span></pre>
514
+
515
+ <!-- Copy Button Mockup -->
516
+ <div
517
+ class="absolute top-3 right-3 opacity-0 group-hover:opacity-100 transition-opacity"
518
+ >
519
+ <button
520
+ class="p-2 rounded-lg bg-white/80 dark:bg-slate-800/80 border border-gray-200 dark:border-slate-700 hover:border-blue-500/50 text-gray-500 dark:text-slate-400 transition-all active:scale-90 shadow-sm"
521
+ >
522
+ <span class="material-symbols-outlined text-[18px]"
523
+ >content_copy</span
524
+ >
525
+ </button>
526
+ </div>
527
+ </div>
528
+ </div>
529
+
530
+ <div>
531
+ <h2
532
+ id="module-overview"
533
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
534
+ >
535
+ Best Practices
536
+ </h2>
537
+ <div class="space-y-4">
538
+ <div
539
+ class="flex gap-4 p-4 rounded-xl bg-gray-50/50 dark:bg-slate-800/30 border border-gray-200 dark:border-slate-800/60"
540
+ >
541
+ <div
542
+ class="w-10 h-10 rounded-lg bg-blue-500/10 flex items-center justify-center text-blue-500"
543
+ >
544
+ <span class="material-symbols-outlined"
545
+ >settings_input_component</span
546
+ >
547
+ </div>
548
+ <div>
549
+ <h3
550
+ class="text-sm font-bold text-gray-950 dark:text-white uppercase tracking-tight"
551
+ >
552
+ Core Layer
553
+ </h3>
554
+ <p class="text-xs text-slate-500 mt-1 leading-relaxed">
555
+ Manages the custom element lifecycle, property-to-state
556
+ mapping via Proxies, and atomic DOM updates through the
557
+ reconciliation engine.
558
+ </p>
559
+ </div>
560
+ </div>
561
+ <div
562
+ class="flex gap-4 p-4 rounded-xl bg-gray-50/50 dark:bg-slate-800/30 border border-gray-200 dark:border-slate-800/60"
563
+ >
564
+ <div
565
+ class="w-10 h-10 rounded-lg bg-emerald-500/10 flex items-center justify-center text-emerald-500"
566
+ >
567
+ <span class="material-symbols-outlined">api</span>
568
+ </div>
569
+ <div>
570
+ <h3
571
+ class="text-sm font-bold text-gray-950 dark:text-white uppercase tracking-tight"
572
+ >
573
+ Common Services
574
+ </h3>
575
+ <p class="text-xs text-slate-500 mt-1 leading-relaxed">
576
+ Provides high-level utilities like the History Router,
577
+ I18n Engine, and HTTP client that integrate seamlessly
578
+ with the reactivity system.
579
+ </p>
580
+ </div>
581
+ </div>
582
+ </div>
583
+ </div>
584
+ </article>
585
+ </if>
586
+
587
+ <!-- ── AI DEVELOPMENT ── -->
588
+ <if condition="{activeTab === 'aidev'}">
589
+ <article class="space-y-10">
590
+ <div>
591
+ <p
592
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
593
+ >
594
+ Getting Started
595
+ </p>
596
+ <h1
597
+ id="ai-intro"
598
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
599
+ >
600
+ AI-First Development
601
+ </h1>
602
+ <p
603
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
604
+ >
605
+ JunoJS is designed to be highly compatible with AI coding
606
+ assistants. By providing structured rule files, you can ensure
607
+ your AI understands the core decorators, reactivity model, and
608
+ architectural patterns of the framework.
609
+ </p>
610
+ </div>
611
+
612
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
613
+
614
+ <!-- Tools Grid -->
615
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
616
+ <!-- Cursor -->
617
+ <div
618
+ class="p-6 rounded-2xl bg-[#fafafa] dark:bg-slate-900/50 border border-gray-200 dark:border-slate-800 hover:border-blue-500/50 transition-all group"
619
+ >
620
+ <div class="flex items-center gap-3 mb-4">
621
+ <div
622
+ class="w-10 h-10 rounded-xl bg-blue-500/10 flex items-center justify-center text-blue-500"
623
+ >
624
+ <span class="material-symbols-outlined">smart_toy</span>
625
+ </div>
626
+ <h3 class="font-bold text-gray-900 dark:text-white">
627
+ Cursor
628
+ </h3>
629
+ </div>
630
+ <p
631
+ class="text-xs text-gray-500 dark:text-slate-400 leading-relaxed mb-4"
632
+ >
633
+ Cursor uses
634
+ <code class="text-blue-500">.cursorrules</code> to provide
635
+ project-specific context and enforce architectural
636
+ standards.
637
+ </p>
638
+ <pre
639
+ class="bg-gray-100 dark:bg-slate-900 border border-gray-200 dark:border-slate-800 rounded-lg p-3 text-[11px] font-mono text-gray-600 dark:text-slate-400"
640
+ >
641
+ # Created in project root
642
+ .cursorrules</pre
643
+ >
644
+ </div>
645
+
646
+ <!-- Windsurf -->
647
+ <div
648
+ class="p-6 rounded-2xl bg-[#fafafa] dark:bg-slate-900/50 border border-gray-200 dark:border-slate-800 hover:border-emerald-500/50 transition-all group"
649
+ >
650
+ <div class="flex items-center gap-3 mb-4">
651
+ <div
652
+ class="w-10 h-10 rounded-xl bg-emerald-500/10 flex items-center justify-center text-emerald-500"
653
+ >
654
+ <span class="material-symbols-outlined">waves</span>
655
+ </div>
656
+ <h3 class="font-bold text-gray-900 dark:text-white">
657
+ Windsurf
658
+ </h3>
659
+ </div>
660
+ <p
661
+ class="text-xs text-gray-500 dark:text-slate-400 leading-relaxed mb-4"
662
+ >
663
+ Windsurf reads
664
+ <code class="text-emerald-500">.windsurfrules</code> to
665
+ align its agentic behavior with the JunoJS lifecycle.
666
+ </p>
667
+ <pre
668
+ class="bg-gray-100 dark:bg-slate-900 border border-gray-200 dark:border-slate-800 rounded-lg p-3 text-[11px] font-mono text-gray-600 dark:text-slate-400"
669
+ >
670
+ # Created in project root
671
+ .windsurfrules</pre
672
+ >
673
+ </div>
674
+ </div>
675
+
676
+ <!-- General AI Models -->
677
+ <div class="space-y-6">
678
+ <h2
679
+ id="custom-instructions"
680
+ class="text-xl font-bold text-gray-900 dark:text-white tracking-tight"
681
+ >
682
+ Large Language Models
683
+ </h2>
684
+ <p
685
+ class="text-sm text-gray-600 dark:text-slate-400 leading-relaxed"
686
+ >
687
+ For models like Claude (Anthropic) and Gemini (Google), you
688
+ can provide framework context via
689
+ <strong>Custom Instructions</strong> or by uploading a system
690
+ prompt.
691
+ </p>
692
+
693
+ <div
694
+ class="bg-gray-50 dark:bg-slate-900/30 border border-gray-200 dark:border-slate-800 rounded-2xl p-6 space-y-4"
695
+ >
696
+ <div class="flex items-start gap-4">
697
+ <div
698
+ class="p-2 rounded-lg bg-orange-500/10 text-orange-500"
699
+ >
700
+ <span class="material-symbols-outlined">description</span>
701
+ </div>
702
+ <div>
703
+ <h4
704
+ class="text-sm font-bold text-gray-900 dark:text-white"
705
+ >
706
+ Core Instructions
707
+ </h4>
708
+ <p
709
+ class="text-xs text-slate-500 mt-1 leading-relaxed italic"
710
+ >
711
+ "Always use @Component for Web Components. In
712
+ JunoJS, use @State() for reactivity. Do NOT use a
713
+ Virtual DOM—the engine reconciles the real DOM using a
714
+ proxy system."
715
+ </p>
716
+ </div>
717
+ </div>
718
+ </div>
719
+ </div>
720
+ </article>
721
+ </if>
722
+
723
+ <!-- ── QUICK START ── -->
724
+ <if condition="{activeTab === 'quickstart'}">
725
+ <article class="space-y-8">
726
+ <div>
727
+ <p
728
+ class="text-xs font-semibold text-blue-600 dark:text-blue-500 uppercase tracking-widest mb-3"
729
+ >
730
+ Getting Started
731
+ </p>
732
+ <h1
733
+ id="quickstart"
734
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
735
+ >
736
+ Quick Start
737
+ </h1>
738
+ <p
739
+ class="text-base text-gray-600 dark:text-slate-400 leading-relaxed"
740
+ >
741
+ Build your first reactive component in under a minute. This
742
+ example demonstrates state, events, and template
743
+ interpolation.
744
+ </p>
745
+ </div>
746
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
747
+ <div>
748
+ <h2
749
+ id="component"
750
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
751
+ >
752
+ Create a Component
753
+ </h2>
754
+ <pre
755
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
756
+ >
757
+ import &#123; Component, State, bootstrap &#125; from '@junojs/core';
758
+
759
+ @Component(&#123;
760
+ tag: 'my-counter',
761
+ shadow: false,
762
+ template: `
763
+ &lt;div&gt;
764
+ &lt;span&gt;&#123;count&#125;&lt;/span&gt;
765
+ &lt;button @click="increment"&gt;+&lt;/button&gt;
766
+ &lt;/div&gt;
767
+ `
768
+ &#125;)
769
+ class MyCounter &#123;
770
+ @State() count = 0;
771
+ increment() &#123; this.count++; &#125;
772
+ &#125;
773
+
774
+ bootstrap(MyCounter);</pre
775
+ >
776
+ </div>
777
+ <div>
778
+ <h2
779
+ id="live"
780
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
781
+ >
782
+ Live Demo
783
+ </h2>
784
+ <div
785
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-xl p-8 flex items-center gap-6"
786
+ >
787
+ <span
788
+ class="text-5xl font-black text-gray-900 dark:text-white tabular-nums w-20 text-center"
789
+ >{counter}</span
790
+ >
791
+ <button
792
+ class="px-6 py-2.5 bg-blue-600 hover:bg-blue-500 text-white text-sm font-semibold rounded-lg transition-colors"
793
+ @click="increment"
794
+ >
795
+ Increment
796
+ </button>
797
+ </div>
798
+ <p class="text-xs text-gray-500 dark:text-slate-500 mt-3">
799
+ Counter value is held in a
800
+ <code class="text-blue-600 dark:text-blue-400">@State()</code>
801
+ property. Every mutation triggers DOM reconciliation
802
+ automatically.
803
+ </p>
804
+ </div>
805
+ </article>
806
+ </if>
807
+
808
+ <!-- ── REACTIVITY ── -->
809
+ <if condition="{activeTab === 'reactivity'}">
810
+ <article class="space-y-8">
811
+ <div>
812
+ <p
813
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
814
+ >
815
+ Core Concepts
816
+ </p>
817
+ <h1
818
+ id="reactivity"
819
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
820
+ >
821
+ Reactivity
822
+ </h1>
823
+ <p
824
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
825
+ >
826
+ JunoJS uses a Proxy-based reactivity model. There is no
827
+ Virtual DOM — mutations are detected directly on the
828
+ JavaScript object and the engine reconciles only what changed
829
+ in the real DOM.
830
+ </p>
831
+ </div>
832
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
833
+ <div>
834
+ <h2
835
+ id="state"
836
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
837
+ >
838
+ @State Decorator
839
+ </h2>
840
+ <p
841
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
842
+ >
843
+ Mark any class property with
844
+ <code class="bg-slate-900 text-blue-400 px-1 rounded text-xs"
845
+ >@State()</code
846
+ >
847
+ to make it reactive. The bootstrap system wraps the component
848
+ instance in a
849
+ <code class="bg-slate-900 text-blue-400 px-1 rounded text-xs"
850
+ >Proxy</code
851
+ >
852
+ that intercepts all property writes.
853
+ </p>
854
+ <pre
855
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
856
+ >
857
+ class MyComponent &#123;
858
+ @State() username = '';
859
+ @State() count = 0;
860
+ @State() isLoading = false;
861
+ &#125;</pre
862
+ >
863
+ </div>
864
+ <div>
865
+ <h2
866
+ id="how"
867
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
868
+ >
869
+ How It Works
870
+ </h2>
871
+ <p class="text-sm text-gray-600 dark:text-slate-400 leading-7">
872
+ When a
873
+ <code
874
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
875
+ >@State</code
876
+ >
877
+ property is written to, the Proxy trap fires the scheduler
878
+ which calls
879
+ <code
880
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
881
+ >update()</code
882
+ >. The
883
+ <code
884
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
885
+ >NeuralEngine</code
886
+ >
887
+ re-renders the template into a virtual string, then the
888
+ <code
889
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
890
+ >reconcile()</code
891
+ >
892
+ function walks the real DOM and patches only nodes that differ
893
+ — no full re-render, no Virtual DOM overhead.
894
+ </p>
895
+ </div>
896
+ <div>
897
+ <h2
898
+ id="persist"
899
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
900
+ >
901
+ Persistent State
902
+ </h2>
903
+ <p
904
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
905
+ >
906
+ Combine
907
+ <code
908
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
909
+ >@State()</code
910
+ >
911
+ with
912
+ <code
913
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
914
+ >@Persist()</code
915
+ >
916
+ to automatically sync a property to
917
+ <code
918
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
919
+ >localStorage</code
920
+ >
921
+ or
922
+ <code
923
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
924
+ >sessionStorage</code
925
+ >.
926
+ </p>
927
+ <pre
928
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
929
+ >
930
+ @State() @Persist('local') theme = 'dark';
931
+ @State() @Persist('session') token = '';</pre
932
+ >
933
+ </div>
934
+ </article>
935
+ </if>
936
+
937
+ <!-- ── TEMPLATES ── -->
938
+ <if condition="{activeTab === 'templates'}">
939
+ <article class="space-y-8">
940
+ <div>
941
+ <p
942
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
943
+ >
944
+ Core Concepts
945
+ </p>
946
+ <h1
947
+ id="templates"
948
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
949
+ >
950
+ Template Syntax
951
+ </h1>
952
+ <p
953
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
954
+ >
955
+ Templates are standard HTML enhanced with interpolation
956
+ expressions and semantic structural tags. No JSX, no
957
+ directives — just HTML that thinks.
958
+ </p>
959
+ </div>
960
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
961
+ <div>
962
+ <h2
963
+ id="interpolation"
964
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
965
+ >
966
+ Interpolation
967
+ </h2>
968
+ <p
969
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
970
+ >
971
+ Any expression wrapped in
972
+ <code
973
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
974
+ >&#123; &#125;</code
975
+ >
976
+ is evaluated against the component context. Supports property
977
+ access, ternaries, and method calls.
978
+ </p>
979
+ <pre
980
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
981
+ >
982
+ &lt;p&gt;Hello, &#123;username&#125;!&lt;/p&gt;
983
+ &lt;span&gt;&#123;count &gt; 0 ? count : 'None'&#125;&lt;/span&gt;
984
+ &lt;img src="&#123;avatarUrl&#125;" alt="&#123;username&#125;" /&gt;</pre
985
+ >
986
+ </div>
987
+ <div>
988
+ <h2
989
+ id="conditionals"
990
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
991
+ >
992
+ Conditionals
993
+ </h2>
994
+ <pre
995
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
996
+ >
997
+ &lt;if condition="&#123;isLoggedIn&#125;"&gt;
998
+ &lt;p&gt;Welcome back, &#123;username&#125;&lt;/p&gt;
999
+ &lt;else&gt;
1000
+ &lt;p&gt;Please sign in.&lt;/p&gt;
1001
+ &lt;/else&gt;
1002
+ &lt;/if&gt;</pre
1003
+ >
1004
+ </div>
1005
+ <div>
1006
+ <h2
1007
+ id="loops"
1008
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1009
+ >
1010
+ Loops
1011
+ </h2>
1012
+ <pre
1013
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1014
+ >
1015
+ &lt;for each="&#123;item in items&#125;"&gt;
1016
+ &lt;li&gt;&#123;item.name&#125; — &#123;item.price&#125;&lt;/li&gt;
1017
+ &lt;/for&gt;</pre
1018
+ >
1019
+ </div>
1020
+ <div>
1021
+ <h2
1022
+ id="events"
1023
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1024
+ >
1025
+ Event Binding
1026
+ </h2>
1027
+ <p
1028
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
1029
+ >
1030
+ Use
1031
+ <code
1032
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1033
+ >@click</code
1034
+ >
1035
+ and
1036
+ <code
1037
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1038
+ >@input</code
1039
+ >
1040
+ attributes. Arguments are parsed and passed to the method
1041
+ automatically.
1042
+ </p>
1043
+ <pre
1044
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1045
+ >
1046
+ &lt;button @click="save"&gt;Save&lt;/button&gt;
1047
+ &lt;button @click="remove(item.id)"&gt;Delete&lt;/button&gt;
1048
+ &lt;input @input="handleInput" /&gt;</pre
1049
+ >
1050
+ </div>
1051
+ </article>
1052
+ </if>
1053
+
1054
+ <!-- ── LIFECYCLE ── -->
1055
+ <if condition="{activeTab === 'lifecycle'}">
1056
+ <article class="space-y-8">
1057
+ <div>
1058
+ <p
1059
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
1060
+ >
1061
+ Core Concepts
1062
+ </p>
1063
+ <h1
1064
+ id="lifecycle"
1065
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
1066
+ >
1067
+ Lifecycle Hooks
1068
+ </h1>
1069
+ <p
1070
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
1071
+ >
1072
+ JunoJS components expose three lifecycle hooks that let
1073
+ you run code at predictable points during a component's
1074
+ lifetime.
1075
+ </p>
1076
+ </div>
1077
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
1078
+ <div class="grid grid-cols-3 gap-4">
1079
+ <div
1080
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-xl p-5 text-center space-y-2"
1081
+ >
1082
+ <p
1083
+ class="text-[10px] font-bold text-blue-500 uppercase tracking-wider"
1084
+ >
1085
+ Pre-render
1086
+ </p>
1087
+ <code
1088
+ class="text-gray-900 dark:text-white font-bold text-sm block"
1089
+ >onInit()</code
1090
+ >
1091
+ <p class="text-[11px] text-slate-500">
1092
+ Async-safe. Runs before first render.
1093
+ </p>
1094
+ </div>
1095
+ <div
1096
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-xl p-5 text-center space-y-2"
1097
+ >
1098
+ <p
1099
+ class="text-[10px] font-bold text-blue-500 uppercase tracking-wider"
1100
+ >
1101
+ Post-render
1102
+ </p>
1103
+ <code
1104
+ class="text-gray-900 dark:text-white font-bold text-sm block"
1105
+ >onRender()</code
1106
+ >
1107
+ <p class="text-[11px] text-slate-500">
1108
+ DOM is live. Safe for direct DOM access.
1109
+ </p>
1110
+ </div>
1111
+ <div
1112
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-xl p-5 text-center space-y-2"
1113
+ >
1114
+ <p
1115
+ class="text-[10px] font-bold text-blue-500 uppercase tracking-wider"
1116
+ >
1117
+ Cleanup
1118
+ </p>
1119
+ <code
1120
+ class="text-gray-900 dark:text-white font-bold text-sm block"
1121
+ >onDestroy()</code
1122
+ >
1123
+ <p class="text-[11px] text-slate-500">
1124
+ Remove timers, subscriptions, listeners.
1125
+ </p>
1126
+ </div>
1127
+ </div>
1128
+ <div>
1129
+ <h2
1130
+ id="example"
1131
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1132
+ >
1133
+ Example
1134
+ </h2>
1135
+ <pre
1136
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1137
+ >
1138
+ class DataComponent &#123;
1139
+ @State() data = [];
1140
+ private timer: number;
1141
+
1142
+ async onInit() &#123;
1143
+ this.data = await fetch('/api/items').then(r =&gt; r.json());
1144
+ &#125;
1145
+
1146
+ onRender(el: HTMLElement) &#123;
1147
+ el.querySelector('input')?.focus();
1148
+ &#125;
1149
+
1150
+ onDestroy() &#123;
1151
+ clearInterval(this.timer);
1152
+ &#125;
1153
+ &#125;</pre
1154
+ >
1155
+ </div>
1156
+ </article>
1157
+ </if>
1158
+
1159
+ <!-- ── HTTP ── -->
1160
+ <if condition="{activeTab === 'http'}">
1161
+ <article class="space-y-8">
1162
+ <div>
1163
+ <p
1164
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
1165
+ >
1166
+ Common Services
1167
+ </p>
1168
+ <h1
1169
+ id="http"
1170
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
1171
+ >
1172
+ HTTP Client
1173
+ </h1>
1174
+ <p
1175
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
1176
+ >
1177
+ A typed, interceptor-based HTTP client built on the Fetch API.
1178
+ Supports auto-JSON serialisation, query params, timeout/abort,
1179
+ and pluggable error handling.
1180
+ </p>
1181
+ </div>
1182
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
1183
+ <div>
1184
+ <h2
1185
+ id="methods"
1186
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1187
+ >
1188
+ Methods
1189
+ </h2>
1190
+ <div class="grid grid-cols-2 gap-3">
1191
+ <div
1192
+ class="bg-slate-900 border border-slate-800 rounded-lg p-4"
1193
+ >
1194
+ <code class="text-blue-400 text-xs font-mono font-bold"
1195
+ >http.get&lt;T&gt;(url, config?)</code
1196
+ >
1197
+ <p
1198
+ class="text-[11px] text-gray-500 dark:text-slate-500 mt-1"
1199
+ >
1200
+ Fetch a resource
1201
+ </p>
1202
+ </div>
1203
+ <div
1204
+ class="bg-slate-900 border border-slate-800 rounded-lg p-4"
1205
+ >
1206
+ <code class="text-blue-400 text-xs font-mono font-bold"
1207
+ >http.post&lt;T&gt;(url, body?)</code
1208
+ >
1209
+ <p
1210
+ class="text-[11px] text-gray-500 dark:text-slate-500 mt-1"
1211
+ >
1212
+ Create a resource
1213
+ </p>
1214
+ </div>
1215
+ <div
1216
+ class="bg-slate-900 border border-slate-800 rounded-lg p-4"
1217
+ >
1218
+ <code class="text-blue-400 text-xs font-mono font-bold"
1219
+ >http.put&lt;T&gt;(url, body?)</code
1220
+ >
1221
+ <p
1222
+ class="text-[11px] text-gray-500 dark:text-slate-500 mt-1"
1223
+ >
1224
+ Replace a resource
1225
+ </p>
1226
+ </div>
1227
+ <div
1228
+ class="bg-slate-900 border border-slate-800 rounded-lg p-4"
1229
+ >
1230
+ <code class="text-blue-400 text-xs font-mono font-bold"
1231
+ >http.patch&lt;T&gt;(url, body?)</code
1232
+ >
1233
+ <p
1234
+ class="text-[11px] text-gray-500 dark:text-slate-500 mt-1"
1235
+ >
1236
+ Partial update
1237
+ </p>
1238
+ </div>
1239
+ <div
1240
+ class="bg-slate-900 border border-slate-800 rounded-lg p-4"
1241
+ >
1242
+ <code class="text-blue-400 text-xs font-mono font-bold"
1243
+ >http.delete&lt;T&gt;(url, config?)</code
1244
+ >
1245
+ <p
1246
+ class="text-[11px] text-gray-500 dark:text-slate-500 mt-1"
1247
+ >
1248
+ Remove a resource
1249
+ </p>
1250
+ </div>
1251
+ </div>
1252
+ </div>
1253
+ <div>
1254
+ <h2
1255
+ id="config"
1256
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1257
+ >
1258
+ RequestConfig
1259
+ </h2>
1260
+ <pre
1261
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1262
+ >
1263
+ &#123;
1264
+ headers?: Record&lt;string, string&gt;
1265
+ params?: Record&lt;string, string&gt; // Appended as query string
1266
+ timeout?: number // ms — auto-aborts request
1267
+ signal?: AbortSignal // External AbortController
1268
+ &#125;</pre
1269
+ >
1270
+ </div>
1271
+ <div>
1272
+ <h2
1273
+ id="interceptors"
1274
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1275
+ >
1276
+ Interceptors
1277
+ </h2>
1278
+ <pre
1279
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1280
+ >
1281
+ // Add auth token to every request
1282
+ http.addRequestInterceptor((url, init) =&gt; &#123;
1283
+ init.headers['Authorization'] = `Bearer $&#123;token&#125;`;
1284
+ return [url, init];
1285
+ &#125;);
1286
+
1287
+ // Handle 401 globally
1288
+ http.addResponseInterceptor((res) =&gt; &#123;
1289
+ if (res.status === 401) router.go('/login');
1290
+ return res;
1291
+ &#125;);</pre
1292
+ >
1293
+ </div>
1294
+ </article>
1295
+ </if>
1296
+
1297
+ <!-- ── I18N ── -->
1298
+ <if condition="{activeTab === 'i18n'}">
1299
+ <article class="space-y-8">
1300
+ <div>
1301
+ <p
1302
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
1303
+ >
1304
+ Common Services
1305
+ </p>
1306
+ <h1
1307
+ id="i18n"
1308
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
1309
+ >
1310
+ Internationalization
1311
+ </h1>
1312
+ <p
1313
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
1314
+ >
1315
+ A singleton i18n service with multi-locale support,
1316
+ <code
1317
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1318
+ >&#123;&#123;param&#125;&#125;</code
1319
+ >
1320
+ interpolation, and reactive locale-change subscriptions.
1321
+ </p>
1322
+ </div>
1323
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
1324
+ <div>
1325
+ <h2
1326
+ id="setup"
1327
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1328
+ >
1329
+ Setup
1330
+ </h2>
1331
+ <pre
1332
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1333
+ >
1334
+ import &#123; I18nService &#125; from '@junojs/common/i18n';
1335
+
1336
+ const i18n = I18nService.instance;
1337
+
1338
+ i18n.addTranslations('en', &#123;
1339
+ greeting: 'Hello, &#123;&#123;name&#125;&#125;!',
1340
+ items: '&#123;&#123;count&#125;&#125; items found',
1341
+ &#125;);
1342
+
1343
+ i18n.addTranslations('de', &#123;
1344
+ greeting: 'Hallo, &#123;&#123;name&#125;&#125;!',
1345
+ &#125;);
1346
+
1347
+ i18n.setLocale('en');</pre
1348
+ >
1349
+ </div>
1350
+ <div>
1351
+ <h2
1352
+ id="translate"
1353
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1354
+ >
1355
+ Translating Keys
1356
+ </h2>
1357
+ <pre
1358
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1359
+ >
1360
+ i18n.t('greeting', &#123; name: 'Ada' &#125;); // "Hello, Ada!"
1361
+ i18n.t('items', &#123; count: 42 &#125;); // "42 items found"
1362
+ i18n.t('unknown.key'); // returns the key itself</pre
1363
+ >
1364
+ </div>
1365
+ <div>
1366
+ <h2
1367
+ id="locale-change"
1368
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1369
+ >
1370
+ Reactive Locale Changes
1371
+ </h2>
1372
+ <pre
1373
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1374
+ >
1375
+ class MyComponent &#123;
1376
+ private unsubscribe: () =&gt; void;
1377
+
1378
+ onInit() &#123;
1379
+ this.unsubscribe = i18n.onLocaleChange(() =&gt; this.update());
1380
+ &#125;
1381
+
1382
+ onDestroy() &#123;
1383
+ this.unsubscribe(); // prevent memory leaks
1384
+ &#125;
1385
+ &#125;</pre
1386
+ >
1387
+ </div>
1388
+ </article>
1389
+ </if>
1390
+
1391
+ <!-- ── FORMS ── -->
1392
+ <if condition="{activeTab === 'forms'}">
1393
+ <article class="space-y-8">
1394
+ <div>
1395
+ <p
1396
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
1397
+ >
1398
+ Common Services
1399
+ </p>
1400
+ <h1
1401
+ id="forms"
1402
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
1403
+ >
1404
+ Forms &amp; Validation
1405
+ </h1>
1406
+ <p
1407
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
1408
+ >
1409
+ Reactive form models with decorator-based validation. Extend
1410
+ <code
1411
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1412
+ >FormModel</code
1413
+ >
1414
+ and annotate fields with built-in validators.
1415
+ </p>
1416
+ </div>
1417
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
1418
+ <div>
1419
+ <h2
1420
+ id="form-model"
1421
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1422
+ >
1423
+ FormModel
1424
+ </h2>
1425
+ <pre
1426
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1427
+ >
1428
+ import &#123; FormModel, Required, Email, Match &#125; from '@junojs/common/forms';
1429
+
1430
+ class RegisterForm extends FormModel &#123;
1431
+ @Required() @Email() email = '';
1432
+ @Required() password = '';
1433
+ @Required() @Match('password', 'Passwords must match')
1434
+ confirmPassword = '';
1435
+ &#125;
1436
+
1437
+ const form = new RegisterForm();
1438
+ form.isValid(); // false (all fields empty)
1439
+ form.getErrors(); // &#123; email: ['...'], password: ['...'] &#125;
1440
+ form.dirty; // false (not changed yet)
1441
+ form.reset(); // restore initial values</pre
1442
+ >
1443
+ </div>
1444
+ <div>
1445
+ <h2
1446
+ id="validators"
1447
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1448
+ >
1449
+ Built-in Validators
1450
+ </h2>
1451
+ <div class="space-y-3">
1452
+ <div
1453
+ class="bg-slate-900 border border-slate-800 rounded-lg p-4 flex gap-4 items-start"
1454
+ >
1455
+ <code
1456
+ class="text-blue-400 text-xs font-mono font-bold whitespace-nowrap"
1457
+ >@Required(msg?)</code
1458
+ >
1459
+ <p
1460
+ class="text-xs text-gray-600 dark:text-slate-400 leading-relaxed mt-0.5"
1461
+ >
1462
+ Field must be non-empty, non-null, and non-undefined.
1463
+ </p>
1464
+ </div>
1465
+ <div
1466
+ class="bg-slate-900 border border-slate-800 rounded-lg p-4 flex gap-4 items-start"
1467
+ >
1468
+ <code
1469
+ class="text-blue-400 text-xs font-mono font-bold whitespace-nowrap"
1470
+ >@Email(msg?)</code
1471
+ >
1472
+ <p
1473
+ class="text-xs text-gray-600 dark:text-slate-400 leading-relaxed mt-0.5"
1474
+ >
1475
+ Must be a valid email address format. Composable with
1476
+ @Required.
1477
+ </p>
1478
+ </div>
1479
+ <div
1480
+ class="bg-slate-900 border border-slate-800 rounded-lg p-4 flex gap-4 items-start"
1481
+ >
1482
+ <code
1483
+ class="text-blue-400 text-xs font-mono font-bold whitespace-nowrap"
1484
+ >@Pattern(regex, msg?)</code
1485
+ >
1486
+ <p
1487
+ class="text-xs text-gray-600 dark:text-slate-400 leading-relaxed mt-0.5"
1488
+ >
1489
+ Field value must match the provided regular expression.
1490
+ </p>
1491
+ </div>
1492
+ <div
1493
+ class="bg-slate-900 border border-slate-800 rounded-lg p-4 flex gap-4 items-start"
1494
+ >
1495
+ <code
1496
+ class="text-blue-400 text-xs font-mono font-bold whitespace-nowrap"
1497
+ >@Match(field, msg?)</code
1498
+ >
1499
+ <p
1500
+ class="text-xs text-gray-600 dark:text-slate-400 leading-relaxed mt-0.5"
1501
+ >
1502
+ Cross-field equality check — e.g. confirm password.
1503
+ </p>
1504
+ </div>
1505
+ </div>
1506
+ </div>
1507
+ </article>
1508
+ </if>
1509
+
1510
+ <!-- ── ROUTER SERVICE ── -->
1511
+ <if condition="{activeTab === 'routing'}">
1512
+ <article class="space-y-8">
1513
+ <div>
1514
+ <p
1515
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
1516
+ >
1517
+ Common Services
1518
+ </p>
1519
+ <h1
1520
+ id="routing"
1521
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
1522
+ >
1523
+ Router Service
1524
+ </h1>
1525
+ <p
1526
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
1527
+ >
1528
+ JunoJS includes a typed
1529
+ <strong class="text-gray-800 dark:text-slate-200"
1530
+ >History-based Router Service</strong
1531
+ >. It synchronizes the browser address bar with internal
1532
+ component state, enabling deep linking and browser history
1533
+ navigation.
1534
+ </p>
1535
+ </div>
1536
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
1537
+
1538
+ <!-- How it works -->
1539
+ <div>
1540
+ <h2
1541
+ id="routing-how"
1542
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1543
+ >
1544
+ How It Works
1545
+ </h2>
1546
+ <p
1547
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
1548
+ >
1549
+ The
1550
+ <code
1551
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs font-mono"
1552
+ >RouterService</code
1553
+ >
1554
+ listens for
1555
+ <code class="text-blue-300">popstate</code> events. When the
1556
+ URL matches a registered route, it notifies subscribers.
1557
+ Components use the
1558
+ <code class="text-blue-300">onRouteMatch</code> hook to sync
1559
+ their internal
1560
+ <code class="text-blue-300">@State</code> properties with the
1561
+ current route.
1562
+ </p>
1563
+ <pre
1564
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1565
+ >
1566
+ import &#123; RouterService &#125; from '@junojs/common/router';
1567
+
1568
+ const router = RouterService.instance;
1569
+
1570
+ // Register routes
1571
+ router.register([
1572
+ &#123; path: '/', tab: 'home', title: 'Home' &#125;,
1573
+ &#123; path: '/docs', tab: 'docs', title: 'Documentation' &#125;,
1574
+ ]);</pre
1575
+ >
1576
+ </div>
1577
+
1578
+ <!-- Navigation -->
1579
+ <div>
1580
+ <h2
1581
+ id="routing-triggers"
1582
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1583
+ >
1584
+ Programmatic Navigation
1585
+ </h2>
1586
+ <p
1587
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
1588
+ >
1589
+ Use the
1590
+ <code class="text-blue-300">navigate(path)</code> method to
1591
+ change routes without a full page reload. This updates the
1592
+ History API and triggers the reconciliation logic.
1593
+ </p>
1594
+ <pre
1595
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1596
+ >
1597
+ router.navigate('/installation');</pre
1598
+ >
1599
+ </div>
1600
+
1601
+ <!-- State Sync -->
1602
+ <div>
1603
+ <h2
1604
+ id="routing-state"
1605
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1606
+ >
1607
+ Component Synchronization
1608
+ </h2>
1609
+ <p
1610
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
1611
+ >
1612
+ Bridging the router to a component's state is simple.
1613
+ Subscribe in <code class="text-blue-300">onInit</code> and
1614
+ update your reactive property.
1615
+ </p>
1616
+ <pre
1617
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1618
+ >
1619
+ class AppDocs &#123;
1620
+ @State() activeTab = 'introduction';
1621
+
1622
+ onInit() &#123;
1623
+ router.onRouteMatch(tab =&gt; this.activeTab = tab);
1624
+ router.init(); // Match initial URL
1625
+ &#125;
1626
+ &#125;</pre
1627
+ >
1628
+ </div>
1629
+
1630
+ <!-- Persisting -->
1631
+ <div>
1632
+ <h2
1633
+ id="routing-persist"
1634
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1635
+ >
1636
+ Persistent Routes
1637
+ </h2>
1638
+ <p
1639
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
1640
+ >
1641
+ Combine with the
1642
+ <code
1643
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs font-mono"
1644
+ >@Persist</code
1645
+ >
1646
+ decorator for tab-scoped persistence that survives refreshes
1647
+ while staying in sync with the address bar.
1648
+ </p>
1649
+ </div>
1650
+ </article>
1651
+ </if>
1652
+
1653
+ <!-- ── DECORATORS ── -->
1654
+ <if condition="{activeTab === 'decorators'}">
1655
+ <article class="space-y-8">
1656
+ <div>
1657
+ <p
1658
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
1659
+ >
1660
+ API Reference
1661
+ </p>
1662
+ <h1
1663
+ id="decorators"
1664
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
1665
+ >
1666
+ Decorators
1667
+ </h1>
1668
+ <p
1669
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
1670
+ >
1671
+ JunoJS is decorator-driven. All framework behaviour is
1672
+ attached to classes and properties via TypeScript decorators
1673
+ backed by
1674
+ <code
1675
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1676
+ >reflect-metadata</code
1677
+ >.
1678
+ </p>
1679
+ </div>
1680
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
1681
+ <div class="space-y-4">
1682
+ <h2
1683
+ id="class-decorators"
1684
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1685
+ >
1686
+ Class Decorators
1687
+ </h2>
1688
+ <div
1689
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-5 space-y-2"
1690
+ >
1691
+ <code class="text-blue-400 font-mono font-bold"
1692
+ >@Component(config)</code
1693
+ >
1694
+ <p
1695
+ class="text-xs text-gray-600 dark:text-slate-400 mt-1 leading-relaxed"
1696
+ >
1697
+ Registers the class as a custom element.
1698
+ <strong class="text-slate-300">tag</strong> (required),
1699
+ <strong class="text-slate-300">template</strong> or
1700
+ <strong class="text-slate-300">templateUrl</strong>,
1701
+ <strong class="text-slate-300">shadow</strong> (default:
1702
+ true).
1703
+ </p>
1704
+ </div>
1705
+ <div
1706
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-5 space-y-2"
1707
+ >
1708
+ <code class="text-blue-400 font-mono font-bold"
1709
+ >@Schema(zodSchema)</code
1710
+ >
1711
+ <p
1712
+ class="text-xs text-gray-600 dark:text-slate-400 mt-1 leading-relaxed"
1713
+ >
1714
+ Attach a Zod-compatible validation schema to the component
1715
+ for use with the built-in
1716
+ <code class="text-blue-300">isValid()</code> method.
1717
+ </p>
1718
+ </div>
1719
+ <div
1720
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-5 space-y-2"
1721
+ >
1722
+ <code class="text-blue-400 font-mono font-bold"
1723
+ >@Refine(options)</code
1724
+ >
1725
+ <p
1726
+ class="text-xs text-gray-600 dark:text-slate-400 mt-1 leading-relaxed"
1727
+ >
1728
+ Cross-field validation at the class level.
1729
+ <strong class="text-slate-300">fields</strong>,
1730
+ <strong class="text-slate-300">validate(data)</strong>, and
1731
+ <strong class="text-slate-300">message</strong>.
1732
+ </p>
1733
+ </div>
1734
+ </div>
1735
+ <div class="space-y-4">
1736
+ <h2
1737
+ id="property-decorators"
1738
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1739
+ >
1740
+ Property Decorators
1741
+ </h2>
1742
+ <div
1743
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-5 space-y-2"
1744
+ >
1745
+ <code class="text-blue-400 font-mono font-bold"
1746
+ >@State()</code
1747
+ >
1748
+ <p class="text-xs text-gray-600 dark:text-slate-400 mt-1">
1749
+ Makes the property reactive. Writes trigger DOM
1750
+ reconciliation.
1751
+ </p>
1752
+ </div>
1753
+ <div
1754
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-5 space-y-2"
1755
+ >
1756
+ <code class="text-blue-400 font-mono font-bold"
1757
+ >@Input()</code
1758
+ >
1759
+ <p class="text-xs text-gray-600 dark:text-slate-400 mt-1">
1760
+ Maps an HTML attribute to a class property. Observed via
1761
+ <code class="text-blue-300">attributeChangedCallback</code>.
1762
+ </p>
1763
+ </div>
1764
+ <div
1765
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-5 space-y-2"
1766
+ >
1767
+ <code class="text-blue-400 font-mono font-bold"
1768
+ >@Persist(storage)</code
1769
+ >
1770
+ <p class="text-xs text-gray-600 dark:text-slate-400 mt-1">
1771
+ Auto-saves to <code class="text-blue-300">'local'</code> or
1772
+ <code class="text-blue-300">'session'</code> storage. Key is
1773
+ auto-derived from class and property name.
1774
+ </p>
1775
+ </div>
1776
+ <div
1777
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-5 space-y-2"
1778
+ >
1779
+ <code class="text-blue-400 font-mono font-bold"
1780
+ >@Transform()</code
1781
+ >
1782
+ <p class="text-xs text-gray-600 dark:text-slate-400 mt-1">
1783
+ Registers a method as a template pipe function, usable as
1784
+ <code class="text-blue-300"
1785
+ >&#123;value | methodName&#125;</code
1786
+ >.
1787
+ </p>
1788
+ </div>
1789
+ <div
1790
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-5 space-y-2"
1791
+ >
1792
+ <code class="text-blue-400 font-mono font-bold"
1793
+ >@Action()</code
1794
+ >
1795
+ <p class="text-xs text-gray-600 dark:text-slate-400 mt-1">
1796
+ Marks a method as an emittable action, usable for
1797
+ inter-component communication.
1798
+ </p>
1799
+ </div>
1800
+ <div
1801
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-5 space-y-2"
1802
+ >
1803
+ <code class="text-blue-400 font-mono font-bold"
1804
+ >@HostElement()</code
1805
+ >
1806
+ <p class="text-xs text-gray-600 dark:text-slate-400 mt-1">
1807
+ Injects the native host HTMLElement into the property.
1808
+ Essential for dispatching bubbling CustomEvents or direct
1809
+ element API access.
1810
+ </p>
1811
+ </div>
1812
+ <div
1813
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-5 space-y-2"
1814
+ >
1815
+ <code class="text-blue-400 font-mono font-bold"
1816
+ >@Use(ServiceClass)</code
1817
+ >
1818
+ <p class="text-xs text-gray-600 dark:text-slate-400 mt-1">
1819
+ Injects a singleton service instance into the property at
1820
+ bootstrap time.
1821
+ </p>
1822
+ </div>
1823
+ </div>
1824
+ </article>
1825
+ </if>
1826
+
1827
+ <!-- ── ENGINE ── -->
1828
+ <if condition="{activeTab === 'engine'}">
1829
+ <article class="space-y-8">
1830
+ <div>
1831
+ <p
1832
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
1833
+ >
1834
+ API Reference
1835
+ </p>
1836
+ <h1
1837
+ id="engine"
1838
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
1839
+ >
1840
+ Engine API
1841
+ </h1>
1842
+ <p
1843
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
1844
+ >
1845
+ The low-level primitives powering JunoJS. You rarely call
1846
+ these directly — but understanding them helps you build more
1847
+ efficient components.
1848
+ </p>
1849
+ </div>
1850
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
1851
+ <div>
1852
+ <h2
1853
+ id="neural-engine"
1854
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1855
+ >
1856
+ NeuralEngine.render()
1857
+ </h2>
1858
+ <p
1859
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
1860
+ >
1861
+ Processes a template string against a context object. Handles
1862
+ interpolation, structural tags, and attribute resolution.
1863
+ Returns an HTML string.
1864
+ </p>
1865
+ <pre
1866
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1867
+ >
1868
+ NeuralEngine.render(templateString, contextObject): string</pre
1869
+ >
1870
+ </div>
1871
+ <div>
1872
+ <h2
1873
+ id="reconcile"
1874
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1875
+ >
1876
+ reconcile()
1877
+ </h2>
1878
+ <p
1879
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
1880
+ >
1881
+ Walks the real DOM tree and patches it to match the new
1882
+ rendered HTML. Only nodes that differ are touched — no full
1883
+ re-mount, no flicker.
1884
+ </p>
1885
+ <pre
1886
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1887
+ >
1888
+ reconcile(target: HTMLElement | ShadowRoot, html: string): void</pre
1889
+ >
1890
+ </div>
1891
+ <div>
1892
+ <h2
1893
+ id="proxy"
1894
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1895
+ >
1896
+ createReactiveProxy()
1897
+ </h2>
1898
+ <p
1899
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
1900
+ >
1901
+ Wraps a component instance in a Proxy. Any write to a
1902
+ <code
1903
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1904
+ >@State</code
1905
+ >
1906
+ property triggers the
1907
+ <code
1908
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1909
+ >onUpdate</code
1910
+ >
1911
+ callback (which calls
1912
+ <code
1913
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1914
+ >update()</code
1915
+ >). Also auto-persists
1916
+ <code
1917
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1918
+ >@Persist</code
1919
+ >
1920
+ properties.
1921
+ </p>
1922
+ <pre
1923
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1924
+ >
1925
+ createReactiveProxy(instance, onUpdate: () =&gt; void): Proxy</pre
1926
+ >
1927
+ </div>
1928
+ <div>
1929
+ <h2
1930
+ id="bootstrap"
1931
+ class="text-lg font-semibold text-gray-900 dark:text-white mb-3"
1932
+ >
1933
+ bootstrap()
1934
+ </h2>
1935
+ <p
1936
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7 mb-4"
1937
+ >
1938
+ Reads the
1939
+ <code
1940
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1941
+ >@Component</code
1942
+ >
1943
+ metadata, defines the custom element via
1944
+ <code
1945
+ class="bg-gray-100 text-blue-600 dark:bg-slate-900 dark:text-blue-400 px-1 rounded text-xs"
1946
+ >customElements.define()</code
1947
+ >, and wires up the full lifecycle.
1948
+ </p>
1949
+ <pre
1950
+ class="bg-gray-50 border border-gray-200 dark:bg-slate-900 dark:border-slate-800 rounded-lg p-4 text-[12px] font-mono text-blue-700 dark:text-blue-300 overflow-x-auto"
1951
+ >
1952
+ bootstrap(ComponentClass: any): void</pre
1953
+ >
1954
+ </div>
1955
+ </article>
1956
+ </if>
1957
+
1958
+ <!-- Prev / Next navigation -->
1959
+ <div
1960
+ class="mt-20 pt-8 border-t border-gray-200 dark:border-slate-800/60 flex items-stretch gap-4"
1961
+ >
1962
+ <if condition="{hasPrev}">
1963
+ <button
1964
+ @click="selectPrev"
1965
+ class="group flex flex-col items-start px-5 py-4 rounded-xl border border-gray-200 hover:border-gray-400 dark:border-slate-800 dark:hover:border-slate-600 transition-all flex-1"
1966
+ >
1967
+ <span
1968
+ class="text-[10px] font-semibold text-gray-400 dark:text-slate-500 uppercase tracking-wider mb-1"
1969
+ >← Previous</span
1970
+ >
1971
+ <span
1972
+ class="text-sm font-medium text-gray-700 dark:text-slate-300 group-hover:text-gray-950 dark:group-hover:text-white transition-colors"
1973
+ >{prevPageName}</span
1974
+ >
1975
+ </button>
1976
+ </if>
1977
+ <if condition="{hasNext}">
1978
+ <button
1979
+ @click="selectNext"
1980
+ class="group flex flex-col items-end px-5 py-4 rounded-xl border border-gray-200 hover:border-gray-400 dark:border-slate-800 dark:hover:border-slate-600 transition-all flex-1 ml-auto"
1981
+ >
1982
+ <span
1983
+ class="text-[10px] font-semibold text-gray-400 dark:text-slate-500 uppercase tracking-wider mb-1"
1984
+ >Next →</span
1985
+ >
1986
+ <span
1987
+ class="text-sm font-medium text-gray-700 dark:text-slate-300 group-hover:text-gray-950 dark:group-hover:text-white transition-colors"
1988
+ >{nextPageName}</span
1989
+ >
1990
+ </button>
1991
+ </if>
1992
+ </div>
1993
+
1994
+ <!-- ── SAMPLES ── -->
1995
+ <if condition="{activeTab === 'samples'}">
1996
+ <article class="space-y-12">
1997
+ <div>
1998
+ <p
1999
+ class="text-xs font-semibold text-blue-500 uppercase tracking-widest mb-3"
2000
+ >
2001
+ Resources
2002
+ </p>
2003
+ <h1
2004
+ id="samples"
2005
+ class="text-3xl font-bold text-gray-950 dark:text-white tracking-tight mb-4"
2006
+ >
2007
+ Samples & Examples
2008
+ </h1>
2009
+ <p
2010
+ class="text-base text-gray-500 dark:text-slate-400 leading-relaxed"
2011
+ >
2012
+ Explore real-world applications and boilerplate examples built
2013
+ with JunoJS to understand best practices for architecture
2014
+ and service integration.
2015
+ </p>
2016
+ </div>
2017
+
2018
+ <div class="h-px bg-gray-200 dark:bg-slate-800/60"></div>
2019
+
2020
+ <!-- NeoStore Sample -->
2021
+ <div
2022
+ class="group relative bg-[#fafafa] dark:bg-slate-900/50 border border-gray-200 dark:border-slate-800 rounded-3xl overflow-hidden hover:border-blue-500/50 transition-all duration-500 p-8"
2023
+ >
2024
+ <div class="flex flex-col md:flex-row gap-10 items-center">
2025
+ <div class="flex-1 space-y-6">
2026
+ <div
2027
+ class="inline-flex items-center gap-2 px-2.5 py-1 rounded-full bg-blue-500/10 border border-blue-500/20 text-[10px] font-bold text-blue-600 dark:text-blue-400 uppercase tracking-widest"
2028
+ >
2029
+ Full Application
2030
+ </div>
2031
+ <h2
2032
+ id="neostore"
2033
+ class="text-2xl font-black text-gray-900 dark:text-white tracking-tighter"
2034
+ >
2035
+ NeoStore Shopping App
2036
+ </h2>
2037
+ <p
2038
+ class="text-sm text-gray-600 dark:text-slate-400 leading-7"
2039
+ >
2040
+ A high-fidelity tech store demonstration featuring a
2041
+ premium dark aesthetic. Showcases global state management,
2042
+ authenticated HTTP requests, and History-based routing.
2043
+ </p>
2044
+
2045
+ <div class="flex flex-wrap gap-2">
2046
+ <span
2047
+ class="px-2 py-1 bg-white dark:bg-slate-900 border border-gray-200 dark:border-slate-800 rounded text-[10px] font-bold text-gray-500 tracking-wider"
2048
+ >TAILWIND CSS</span
2049
+ >
2050
+ <span
2051
+ class="px-2 py-1 bg-white dark:bg-slate-900 border border-gray-200 dark:border-slate-800 rounded text-[10px] font-bold text-gray-500 tracking-wider"
2052
+ >ROUTING</span
2053
+ >
2054
+ <span
2055
+ class="px-2 py-1 bg-white dark:bg-slate-900 border border-gray-200 dark:border-slate-800 rounded text-[10px] font-bold text-gray-500 tracking-wider"
2056
+ >I18N</span
2057
+ >
2058
+ <span
2059
+ class="px-2 py-1 bg-white dark:bg-slate-900 border border-gray-200 dark:border-slate-800 rounded text-[10px] font-bold text-gray-500 tracking-wider"
2060
+ >HTTP</span
2061
+ >
2062
+ </div>
2063
+
2064
+ <a
2065
+ href="/samples/shopping-app/index.html"
2066
+ target="_blank"
2067
+ class="inline-flex items-center gap-3 px-6 py-3 bg-blue-600 hover:bg-blue-500 text-white text-xs font-bold rounded-xl shadow-lg shadow-blue-600/20 active:scale-95 transition-all"
2068
+ >
2069
+ Open Live Project
2070
+ <span class="material-symbols-outlined text-sm"
2071
+ >open_in_new</span
2072
+ >
2073
+ </a>
2074
+ </div>
2075
+ <div
2076
+ class="w-full md:w-64 aspect-square rounded-2xl bg-gray-200 dark:bg-slate-800 overflow-hidden border border-gray-200 dark:border-slate-700/50"
2077
+ >
2078
+ <img
2079
+ src="https://images.unsplash.com/photo-1550745165-9bc0b252726f?auto=format&fit=crop&q=80&w=400&h=400"
2080
+ alt="Tech Store"
2081
+ class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700 opacity-60"
2082
+ />
2083
+ </div>
2084
+ </div>
2085
+ </div>
2086
+
2087
+ <!-- More coming soon -->
2088
+ <div
2089
+ class="flex flex-col items-center justify-center p-12 border-2 border-dashed border-gray-200 dark:border-slate-800 rounded-3xl text-center space-y-3"
2090
+ >
2091
+ <p
2092
+ class="text-sm font-semibold text-gray-500 dark:text-slate-400"
2093
+ >
2094
+ More samples coming soon
2095
+ </p>
2096
+ <p class="text-xs text-gray-400 dark:text-slate-600">
2097
+ We are working on Dashboard, Chat, and AI-integrations
2098
+ samples.
2099
+ </p>
2100
+ </div>
2101
+ </article>
2102
+ </if>
2103
+ </div>
2104
+ </main>
2105
+
2106
+ <!-- Right ToC -->
2107
+ <aside class="hidden xl:block w-52 flex-shrink-0 py-14 pr-8">
2108
+ <div class="sticky top-28">
2109
+ <p
2110
+ class="text-[10.5px] font-semibold text-gray-400 dark:text-slate-500 uppercase tracking-widest mb-4"
2111
+ >
2112
+ On This Page
2113
+ </p>
2114
+ <if condition="{activeTab === 'introduction'}">
2115
+ <ul class="space-y-2.5">
2116
+ <li>
2117
+ <a
2118
+ href="#overview"
2119
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2120
+ >Overview</a
2121
+ >
2122
+ </li>
2123
+ <li>
2124
+ <a
2125
+ href="#features"
2126
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2127
+ >Key Features</a
2128
+ >
2129
+ </li>
2130
+ <li>
2131
+ <a
2132
+ href="#architecture"
2133
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2134
+ >Architecture</a
2135
+ >
2136
+ </li>
2137
+ </ul>
2138
+ </if>
2139
+ <if condition="{activeTab === 'installation'}">
2140
+ <ul class="space-y-2.5">
2141
+ <li>
2142
+ <a
2143
+ href="#install"
2144
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2145
+ >Install Package</a
2146
+ >
2147
+ </li>
2148
+ <li>
2149
+ <a
2150
+ href="#tsconfig"
2151
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2152
+ >TypeScript Config</a
2153
+ >
2154
+ </li>
2155
+ <li>
2156
+ <a
2157
+ href="#entry"
2158
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2159
+ >Entry Point</a
2160
+ >
2161
+ </li>
2162
+ </ul>
2163
+ </if>
2164
+ <if condition="{activeTab === 'structure'}">
2165
+ <ul class="space-y-2.5">
2166
+ <li>
2167
+ <a
2168
+ href="#app-structure"
2169
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2170
+ >Project Structure</a
2171
+ >
2172
+ </li>
2173
+ <li>
2174
+ <a
2175
+ href="#module-overview"
2176
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2177
+ >Best Practices</a
2178
+ >
2179
+ </li>
2180
+ </ul>
2181
+ </if>
2182
+ <if condition="{activeTab === 'aidev'}">
2183
+ <ul class="space-y-2.5">
2184
+ <li>
2185
+ <a
2186
+ href="#ai-intro"
2187
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2188
+ >AI-First Dev</a
2189
+ >
2190
+ </li>
2191
+ <li>
2192
+ <a
2193
+ href="#custom-instructions"
2194
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2195
+ >Custom Instructions</a
2196
+ >
2197
+ </li>
2198
+ </ul>
2199
+ </if>
2200
+ <if condition="{activeTab === 'quickstart'}">
2201
+ <ul class="space-y-2.5">
2202
+ <li>
2203
+ <a
2204
+ href="#component"
2205
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2206
+ >Create a Component</a
2207
+ >
2208
+ </li>
2209
+ <li>
2210
+ <a
2211
+ href="#live"
2212
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2213
+ >Live Demo</a
2214
+ >
2215
+ </li>
2216
+ </ul>
2217
+ </if>
2218
+ <if condition="{activeTab === 'forms'}">
2219
+ <ul class="space-y-2.5">
2220
+ <li>
2221
+ <a
2222
+ href="#form-model"
2223
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2224
+ >FormModel</a
2225
+ >
2226
+ </li>
2227
+ <li>
2228
+ <a
2229
+ href="#validators"
2230
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2231
+ >Built-in Validators</a
2232
+ >
2233
+ </li>
2234
+ </ul>
2235
+ </if>
2236
+ <if condition="{activeTab === 'routing'}">
2237
+ <ul class="space-y-2.5">
2238
+ <li>
2239
+ <a
2240
+ href="#routing-how"
2241
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2242
+ >How It Works</a
2243
+ >
2244
+ </li>
2245
+ <li>
2246
+ <a
2247
+ href="#routing-how"
2248
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2249
+ >Registration</a
2250
+ >
2251
+ </li>
2252
+ <li>
2253
+ <a
2254
+ href="#routing-triggers"
2255
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2256
+ >Navigation</a
2257
+ >
2258
+ </li>
2259
+ <li>
2260
+ <a
2261
+ href="#routing-state"
2262
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2263
+ >Component Sync</a
2264
+ >
2265
+ </li>
2266
+ </ul>
2267
+ </if>
2268
+ <if condition="{activeTab === 'reactivity'}">
2269
+ <ul class="space-y-2.5">
2270
+ <li>
2271
+ <a
2272
+ href="#state"
2273
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2274
+ >@State Decorator</a
2275
+ >
2276
+ </li>
2277
+ <li>
2278
+ <a
2279
+ href="#how"
2280
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2281
+ >How It Works</a
2282
+ >
2283
+ </li>
2284
+ <li>
2285
+ <a
2286
+ href="#persist"
2287
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2288
+ >Persistent State</a
2289
+ >
2290
+ </li>
2291
+ </ul>
2292
+ </if>
2293
+ <if condition="{activeTab === 'templates'}">
2294
+ <ul class="space-y-2.5">
2295
+ <li>
2296
+ <a
2297
+ href="#interpolation"
2298
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2299
+ >Interpolation</a
2300
+ >
2301
+ </li>
2302
+ <li>
2303
+ <a
2304
+ href="#conditionals"
2305
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2306
+ >Conditionals</a
2307
+ >
2308
+ </li>
2309
+ <li>
2310
+ <a
2311
+ href="#loops"
2312
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2313
+ >Loops</a
2314
+ >
2315
+ </li>
2316
+ <li>
2317
+ <a
2318
+ href="#events"
2319
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2320
+ >Event Binding</a
2321
+ >
2322
+ </li>
2323
+ </ul>
2324
+ </if>
2325
+ <if condition="{activeTab === 'lifecycle'}">
2326
+ <ul class="space-y-2.5">
2327
+ <li>
2328
+ <a
2329
+ href="#lifecycle"
2330
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2331
+ >Hooks Overview</a
2332
+ >
2333
+ </li>
2334
+ <li>
2335
+ <a
2336
+ href="#example"
2337
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2338
+ >Full Example</a
2339
+ >
2340
+ </li>
2341
+ </ul>
2342
+ </if>
2343
+ <if condition="{activeTab === 'http'}">
2344
+ <ul class="space-y-2.5">
2345
+ <li>
2346
+ <a
2347
+ href="#methods"
2348
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2349
+ >Methods</a
2350
+ >
2351
+ </li>
2352
+ <li>
2353
+ <a
2354
+ href="#config"
2355
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2356
+ >RequestConfig</a
2357
+ >
2358
+ </li>
2359
+ <li>
2360
+ <a
2361
+ href="#interceptors"
2362
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2363
+ >Interceptors</a
2364
+ >
2365
+ </li>
2366
+ </ul>
2367
+ </if>
2368
+ <if condition="{activeTab === 'i18n'}">
2369
+ <ul class="space-y-2.5">
2370
+ <li>
2371
+ <a
2372
+ href="#setup"
2373
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2374
+ >Setup</a
2375
+ >
2376
+ </li>
2377
+ <li>
2378
+ <a
2379
+ href="#translate"
2380
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2381
+ >Translating Keys</a
2382
+ >
2383
+ </li>
2384
+ <li>
2385
+ <a
2386
+ href="#locale-change"
2387
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2388
+ >Reactive Changes</a
2389
+ >
2390
+ </li>
2391
+ </ul>
2392
+ </if>
2393
+ <if condition="{activeTab === 'forms'}">
2394
+ <ul class="space-y-2.5">
2395
+ <li>
2396
+ <a
2397
+ href="#form-model"
2398
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2399
+ >FormModel</a
2400
+ >
2401
+ </li>
2402
+ <li>
2403
+ <a
2404
+ href="#validators"
2405
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2406
+ >Built-in Validators</a
2407
+ >
2408
+ </li>
2409
+ </ul>
2410
+ </if>
2411
+ <if condition="{activeTab === 'decorators'}">
2412
+ <ul class="space-y-2.5">
2413
+ <li>
2414
+ <a
2415
+ href="#class-decorators"
2416
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2417
+ >Class Decorators</a
2418
+ >
2419
+ </li>
2420
+ <li>
2421
+ <a
2422
+ href="#property-decorators"
2423
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2424
+ >Property Decorators</a
2425
+ >
2426
+ </li>
2427
+ </ul>
2428
+ </if>
2429
+ <if condition="{activeTab === 'engine'}">
2430
+ <ul class="space-y-2.5">
2431
+ <li>
2432
+ <a
2433
+ href="#neural-engine"
2434
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2435
+ >NeuralEngine.render</a
2436
+ >
2437
+ </li>
2438
+ <li>
2439
+ <a
2440
+ href="#reconcile"
2441
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2442
+ >reconcile()</a
2443
+ >
2444
+ </li>
2445
+ <li>
2446
+ <a
2447
+ href="#proxy"
2448
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2449
+ >createReactiveProxy</a
2450
+ >
2451
+ </li>
2452
+ <li>
2453
+ <a
2454
+ href="#bootstrap"
2455
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2456
+ >bootstrap()</a
2457
+ >
2458
+ </li>
2459
+ </ul>
2460
+ </if>
2461
+ <if condition="{activeTab === 'samples'}">
2462
+ <ul class="space-y-2.5">
2463
+ <li>
2464
+ <a
2465
+ href="#samples"
2466
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2467
+ >Overview</a
2468
+ >
2469
+ </li>
2470
+ <li>
2471
+ <a
2472
+ href="#neostore"
2473
+ class="text-xs text-gray-400 dark:text-slate-500 hover:text-gray-900 dark:hover:text-slate-200 transition-colors"
2474
+ >NeoStore App</a
2475
+ >
2476
+ </li>
2477
+ </ul>
2478
+ </if>
2479
+ </div>
2480
+ </aside>
2481
+ </div>
2482
+ </div>
2483
+ </div>