fusee-framework 1.6.0 → 1.7.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.
Files changed (112) hide show
  1. package/README.md +29 -13
  2. package/app/benchmark/benchmark.js +633 -0
  3. package/app/benchmark/index.html +102 -0
  4. package/app/benchmark/styles.css +249 -0
  5. package/app/components/Counter.js +17 -7
  6. package/app/components/CounterSection.js +3 -4
  7. package/app/main.js +29 -62
  8. package/app/main.ts +72 -63
  9. package/app/pages/404.js +16 -0
  10. package/app/pages/[...all].js +35 -0
  11. package/app/pages/[...all].ts +35 -0
  12. package/app/pages/_layout.js +26 -0
  13. package/app/pages/_layout.ts +26 -0
  14. package/app/pages/about.js +23 -0
  15. package/app/pages/about.ts +29 -0
  16. package/app/pages/composables.js +158 -0
  17. package/app/pages/composables.ts +158 -0
  18. package/app/pages/dynamic.js +40 -0
  19. package/app/pages/dynamic.ts +40 -0
  20. package/app/pages/index.js +117 -0
  21. package/app/pages/index.ts +78 -0
  22. package/app/pages/login.ts +21 -0
  23. package/app/pages/objects/[id].js +56 -0
  24. package/app/pages/objects/[id].ts +56 -0
  25. package/app/pages/posts/[category]/[slug].js +56 -0
  26. package/app/pages/posts/[category]/[slug].ts +56 -0
  27. package/app/pages/router-example.js +56 -0
  28. package/app/pages/router-example.ts +56 -0
  29. package/app/pages/test-for.js +65 -0
  30. package/app/pages/test-for.ts +80 -0
  31. package/app/pages/users/[id].js +24 -0
  32. package/app/pages/users/[id].ts +46 -0
  33. package/app/pages/users/index.js +22 -0
  34. package/app/pages/users/index.ts +29 -0
  35. package/app/pages/users.js +43 -0
  36. package/app/pages/users.ts +78 -0
  37. package/app/routes/About.js +1 -1
  38. package/app/routes/About.ts +1 -1
  39. package/app/routes/AuthRoutes.ts +41 -0
  40. package/app/routes/Home.js +9 -0
  41. package/app/routes/NotFound.js +16 -0
  42. package/app/routes/NotFound.ts +16 -0
  43. package/app/routes/RouterExample.js +56 -0
  44. package/app/routes/RouterExample.ts +56 -0
  45. package/app/routes/WildcardDemo.js +35 -0
  46. package/app/routes/WildcardDemo.ts +35 -0
  47. package/auto-imports.d.ts +1 -0
  48. package/bin/create-fusee-linux +0 -0
  49. package/bin/create-fusee-mac-arm64 +0 -0
  50. package/bin/create-fusee-mac-intel +0 -0
  51. package/bin/create-fusee-win.exe +0 -0
  52. package/bin/create-fusee.exe +0 -0
  53. package/bin/index.js +38 -0
  54. package/create-fusee-go/cmd/generate.go +72 -0
  55. package/create-fusee-go/cmd/init.go +38 -0
  56. package/create-fusee-go/cmd/root.go +121 -0
  57. package/create-fusee-go/go.mod +10 -0
  58. package/create-fusee-go/go.sum +10 -0
  59. package/create-fusee-go/internal/assets/assets.go +78 -0
  60. package/create-fusee-go/internal/assets/embed/framework/auto-import-preset.js +9 -0
  61. package/create-fusee-go/internal/assets/embed/framework/core/compiler.js +253 -0
  62. package/create-fusee-go/internal/assets/embed/framework/core/component.js +266 -0
  63. package/create-fusee-go/internal/assets/embed/framework/core/composable.js +27 -0
  64. package/create-fusee-go/internal/assets/embed/framework/core/directives.js +875 -0
  65. package/create-fusee-go/internal/assets/embed/framework/core/evaluator.js +153 -0
  66. package/create-fusee-go/internal/assets/embed/framework/core/event-delegation.js +191 -0
  67. package/create-fusee-go/internal/assets/embed/framework/core/signal.js +412 -0
  68. package/create-fusee-go/internal/assets/embed/framework/core/store.js +81 -0
  69. package/create-fusee-go/internal/assets/embed/framework/index.d.ts +3 -0
  70. package/create-fusee-go/internal/assets/embed/framework/index.js +10 -0
  71. package/create-fusee-go/internal/assets/embed/framework/router/file-router.js +177 -0
  72. package/create-fusee-go/internal/assets/embed/framework/router/router.js +462 -0
  73. package/create-fusee-go/internal/assets/embed/framework/types/compiler.d.ts +15 -0
  74. package/create-fusee-go/internal/assets/embed/framework/types/component.d.ts +88 -0
  75. package/create-fusee-go/internal/assets/embed/framework/types/composable.d.ts +14 -0
  76. package/create-fusee-go/internal/assets/embed/framework/types/directives.d.ts +55 -0
  77. package/create-fusee-go/internal/assets/embed/framework/types/evaluator.d.ts +13 -0
  78. package/create-fusee-go/internal/assets/embed/framework/types/event-delegation.d.ts +32 -0
  79. package/create-fusee-go/internal/assets/embed/framework/types/index.d.ts +22 -0
  80. package/create-fusee-go/internal/assets/embed/framework/types/router.d.ts +32 -0
  81. package/create-fusee-go/internal/assets/embed/framework/types/signal.d.ts +79 -0
  82. package/create-fusee-go/internal/assets/embed/framework/types/store.d.ts +8 -0
  83. package/create-fusee-go/internal/assets/templates/Counter.tmpl +26 -0
  84. package/create-fusee-go/internal/assets/templates/component.tmpl +11 -0
  85. package/create-fusee-go/internal/assets/templates/components/Loading.tmpl +24 -0
  86. package/create-fusee-go/internal/assets/templates/index.html.tmpl +15 -0
  87. package/create-fusee-go/internal/assets/templates/main.tmpl +14 -0
  88. package/create-fusee-go/internal/assets/templates/package.json.tmpl +14 -0
  89. package/create-fusee-go/internal/assets/templates/page.tmpl +12 -0
  90. package/create-fusee-go/internal/assets/templates/pages/about.tmpl +20 -0
  91. package/create-fusee-go/internal/assets/templates/pages/index.tmpl +22 -0
  92. package/create-fusee-go/internal/assets/templates/pages/layout.tmpl +18 -0
  93. package/create-fusee-go/internal/assets/templates/tsconfig.json.tmpl +14 -0
  94. package/create-fusee-go/internal/assets/templates/vite.config.js.tmpl +18 -0
  95. package/create-fusee-go/main.go +7 -0
  96. package/framework/auto-import-preset.js +1 -1
  97. package/framework/core/compiler.js +252 -249
  98. package/framework/core/component.js +265 -260
  99. package/framework/core/directives.js +875 -786
  100. package/framework/core/evaluator.js +153 -70
  101. package/framework/core/event-delegation.js +33 -14
  102. package/framework/core/signal.js +412 -403
  103. package/framework/index.js +10 -11
  104. package/framework/router/file-router.js +177 -0
  105. package/framework/router/router.js +462 -80
  106. package/framework/types/event-delegation.d.ts +0 -58
  107. package/framework/types/router.d.ts +32 -15
  108. package/framework/types/signal.d.ts +1 -0
  109. package/index.html +638 -626
  110. package/package.json +5 -3
  111. package/tsconfig.json +1 -0
  112. /package/{framework → create-fusee-go/internal/assets/embed/framework}/bin/create-fusee.js +0 -0
@@ -0,0 +1,102 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Fusée Framework Benchmark</title>
7
+ <link rel="stylesheet" href="styles.css">
8
+ </head>
9
+ <body>
10
+ <div class="container">
11
+ <header>
12
+ <h1>Fusée Framework Benchmark</h1>
13
+ <p>JS Framework Benchmark style - Reactivity + Rendering</p>
14
+ </header>
15
+
16
+ <div class="controls">
17
+ <button id="runFusée" class="btn btn-mode active">Fusée Framework</button>
18
+ <button id="runVanilla" class="btn btn-mode">Vanilla JS</button>
19
+ <button id="runAll" class="btn btn-primary">Run All Benchmarks</button>
20
+ <button id="clear" class="btn btn-secondary">Clear Results</button>
21
+ </div>
22
+
23
+ <div class="benchmarks">
24
+ <div class="benchmark-card" data-benchmark="create">
25
+ <h3>Create Rows</h3>
26
+ <p>Create 1,000 rows with f-for rendering</p>
27
+ <button class="btn btn-small run-benchmark">Run</button>
28
+ <div class="result"></div>
29
+ </div>
30
+
31
+ <div class="benchmark-card" data-benchmark="replace">
32
+ <h3>Replace All Rows</h3>
33
+ <p>Update all 1,000 rows</p>
34
+ <button class="btn btn-small run-benchmark">Run</button>
35
+ <div class="result"></div>
36
+ </div>
37
+
38
+ <div class="benchmark-card" data-benchmark="partial">
39
+ <h3>Partial Update</h3>
40
+ <p>Update every 10th row (100 rows)</p>
41
+ <button class="btn btn-small run-benchmark">Run</button>
42
+ <div class="result"></div>
43
+ </div>
44
+
45
+ <div class="benchmark-card" data-benchmark="select">
46
+ <h3>Select Row</h3>
47
+ <p>Highlight selected row with :class binding</p>
48
+ <button class="btn btn-small run-benchmark">Run</button>
49
+ <div class="result"></div>
50
+ </div>
51
+
52
+ <div class="benchmark-card" data-benchmark="swap">
53
+ <h3>Swap Rows</h3>
54
+ <p>Swap row 2 and row 999</p>
55
+ <button class="btn btn-small run-benchmark">Run</button>
56
+ <div class="result"></div>
57
+ </div>
58
+
59
+ <div class="benchmark-card" data-benchmark="remove">
60
+ <h3>Remove Row</h3>
61
+ <p>Remove one row from 1,000</p>
62
+ <button class="btn btn-small run-benchmark">Run</button>
63
+ <div class="result"></div>
64
+ </div>
65
+
66
+ <div class="benchmark-card" data-benchmark="createMany">
67
+ <h3>Create Many Rows</h3>
68
+ <p>Create 10,000 rows (stress test)</p>
69
+ <button class="btn btn-small run-benchmark">Run</button>
70
+ <div class="result"></div>
71
+ </div>
72
+
73
+ <div class="benchmark-card" data-benchmark="append">
74
+ <h3>Append Rows</h3>
75
+ <p>Append 1,000 to 1,000 existing rows</p>
76
+ <button class="btn btn-small run-benchmark">Run</button>
77
+ <div class="result"></div>
78
+ </div>
79
+
80
+ <div class="benchmark-card" data-benchmark="clear">
81
+ <h3>Clear Rows</h3>
82
+ <p>Clear 1,000 rows</p>
83
+ <button class="btn btn-small run-benchmark">Run</button>
84
+ <div class="result"></div>
85
+ </div>
86
+ </div>
87
+
88
+ <div class="summary">
89
+ <h2>Summary</h2>
90
+ <div id="wgmResult"></div>
91
+ <div id="details"></div>
92
+ </div>
93
+
94
+ <div class="preview">
95
+ <h2>Live Preview</h2>
96
+ <div id="previewContainer"></div>
97
+ </div>
98
+ </div>
99
+
100
+ <script type="module" src="benchmark.js"></script>
101
+ </body>
102
+ </html>
@@ -0,0 +1,249 @@
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
9
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
10
+ min-height: 100vh;
11
+ padding: 20px;
12
+ }
13
+
14
+ .container {
15
+ max-width: 1400px;
16
+ margin: 0 auto;
17
+ }
18
+
19
+ header {
20
+ text-align: center;
21
+ color: white;
22
+ margin-bottom: 30px;
23
+ }
24
+
25
+ header h1 {
26
+ font-size: 2.5rem;
27
+ margin-bottom: 10px;
28
+ }
29
+
30
+ header p {
31
+ font-size: 1.1rem;
32
+ opacity: 0.9;
33
+ }
34
+
35
+ .controls {
36
+ display: flex;
37
+ gap: 10px;
38
+ justify-content: center;
39
+ margin-bottom: 30px;
40
+ }
41
+
42
+ .btn {
43
+ padding: 12px 24px;
44
+ border: none;
45
+ border-radius: 8px;
46
+ font-size: 1rem;
47
+ font-weight: 600;
48
+ cursor: pointer;
49
+ transition: all 0.2s;
50
+ }
51
+
52
+ .btn-primary {
53
+ background: white;
54
+ color: #667eea;
55
+ }
56
+
57
+ .btn-primary:hover {
58
+ background: #f0f0f0;
59
+ transform: translateY(-2px);
60
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
61
+ }
62
+
63
+ .btn-secondary {
64
+ background: rgba(255, 255, 255, 0.2);
65
+ color: white;
66
+ border: 2px solid white;
67
+ }
68
+
69
+ .btn-secondary:hover {
70
+ background: rgba(255, 255, 255, 0.3);
71
+ }
72
+
73
+ .btn-mode {
74
+ background: rgba(255, 255, 255, 0.2);
75
+ color: white;
76
+ border: 2px solid white;
77
+ margin-right: 10px;
78
+ }
79
+
80
+ .btn-mode:hover {
81
+ background: rgba(255, 255, 255, 0.3);
82
+ }
83
+
84
+ .btn-mode.active {
85
+ background: white;
86
+ color: #667eea;
87
+ }
88
+
89
+ .btn-small {
90
+ padding: 8px 16px;
91
+ font-size: 0.9rem;
92
+ }
93
+
94
+ .benchmarks {
95
+ display: grid;
96
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
97
+ gap: 20px;
98
+ margin-bottom: 30px;
99
+ }
100
+
101
+ .benchmark-card {
102
+ background: white;
103
+ border-radius: 12px;
104
+ padding: 20px;
105
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
106
+ transition: transform 0.2s;
107
+ }
108
+
109
+ .benchmark-card:hover {
110
+ transform: translateY(-4px);
111
+ box-shadow: 0 8px 12px rgba(0, 0, 0, 0.15);
112
+ }
113
+
114
+ .benchmark-card h3 {
115
+ color: #667eea;
116
+ margin-bottom: 8px;
117
+ font-size: 1.2rem;
118
+ }
119
+
120
+ .benchmark-card p {
121
+ color: #666;
122
+ margin-bottom: 15px;
123
+ font-size: 0.9rem;
124
+ }
125
+
126
+ .benchmark-card .run-benchmark {
127
+ background: #667eea;
128
+ color: white;
129
+ margin-bottom: 10px;
130
+ }
131
+
132
+ .benchmark-card .run-benchmark:hover {
133
+ background: #5568d3;
134
+ }
135
+
136
+ .result {
137
+ font-size: 1.1rem;
138
+ font-weight: 600;
139
+ color: #333;
140
+ min-height: 24px;
141
+ }
142
+
143
+ .result .time {
144
+ color: #667eea;
145
+ }
146
+
147
+ .result .status {
148
+ font-size: 0.9rem;
149
+ font-weight: 400;
150
+ color: #666;
151
+ }
152
+
153
+ .summary {
154
+ background: white;
155
+ border-radius: 12px;
156
+ padding: 25px;
157
+ margin-bottom: 30px;
158
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
159
+ }
160
+
161
+ .summary h2 {
162
+ color: #667eea;
163
+ margin-bottom: 20px;
164
+ font-size: 1.5rem;
165
+ }
166
+
167
+ #wgmResult {
168
+ font-size: 1.5rem;
169
+ font-weight: 700;
170
+ margin-bottom: 15px;
171
+ color: #333;
172
+ }
173
+
174
+ #wgmResult .score {
175
+ color: #667eea;
176
+ }
177
+
178
+ #wgmResult .indicator {
179
+ font-size: 1.2rem;
180
+ }
181
+
182
+ #details {
183
+ margin-top: 15px;
184
+ }
185
+
186
+ #details table {
187
+ width: 100%;
188
+ border-collapse: collapse;
189
+ }
190
+
191
+ #details th,
192
+ #details td {
193
+ padding: 10px;
194
+ text-align: left;
195
+ border-bottom: 1px solid #eee;
196
+ }
197
+
198
+ #details th {
199
+ font-weight: 600;
200
+ color: #667eea;
201
+ }
202
+
203
+ .preview {
204
+ background: white;
205
+ border-radius: 12px;
206
+ padding: 25px;
207
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
208
+ }
209
+
210
+ .preview h2 {
211
+ color: #667eea;
212
+ margin-bottom: 15px;
213
+ font-size: 1.5rem;
214
+ }
215
+
216
+ #previewContainer {
217
+ max-height: 400px;
218
+ overflow-y: auto;
219
+ border: 1px solid #eee;
220
+ border-radius: 8px;
221
+ padding: 15px;
222
+ }
223
+
224
+ #previewContainer table {
225
+ width: 100%;
226
+ border-collapse: collapse;
227
+ }
228
+
229
+ #previewContainer th,
230
+ #previewContainer td {
231
+ padding: 8px 12px;
232
+ text-align: left;
233
+ border-bottom: 1px solid #eee;
234
+ }
235
+
236
+ #previewContainer th {
237
+ background: #f8f9fa;
238
+ font-weight: 600;
239
+ color: #333;
240
+ }
241
+
242
+ #previewContainer tr.selected {
243
+ background: #667eea;
244
+ color: white;
245
+ }
246
+
247
+ #previewContainer tr.selected td {
248
+ color: white;
249
+ }
@@ -39,9 +39,19 @@ export const Counter = defineComponent({
39
39
  })
40
40
  }
41
41
 
42
- function increment() { count(count() + 1) }
43
- function decrement() { count(count() - 1) }
44
- function reset() { count(0) }
42
+ function increment() {
43
+ console.log('[Counter] increment called, current:', count())
44
+ count(count() + 1)
45
+ console.log('[Counter] after increment:', count())
46
+ }
47
+ function decrement() {
48
+ console.log('[Counter] decrement called')
49
+ count(count() - 1)
50
+ }
51
+ function reset() {
52
+ console.log('[Counter] reset called')
53
+ count(0)
54
+ }
45
55
 
46
56
  onMount(() => console.log('[Counter] mounted, initial:', count()))
47
57
  onUnmount(() => console.log('[Counter] unmounted'))
@@ -76,10 +86,10 @@ export const Counter = defineComponent({
76
86
  <p class="derived">double: {{ double }}</p>
77
87
 
78
88
  <div class="actions">
79
- <button @click.prevent="decrement">−</button>
80
- <button @click.once="reset" :disabled="isZero">Reset (Once only demo)</button>
81
- <button @click="increment">+</button>
82
- <button @click="updateMultiple">+5 & Step (Batched)</button>
89
+ <button on:click.prevent="decrement">−</button>
90
+ <button on:click.once="reset" :disabled="isZero">Reset (Once only demo)</button>
91
+ <button on:click="increment">+</button>
92
+ <button on:click="updateMultiple">+5 & Step (Batched)</button>
83
93
  </div>
84
94
 
85
95
  <div class="extras" style="margin-top: 24px; border-top: 1px solid rgba(0,0,0,0.08); padding-top: 20px;">
@@ -8,17 +8,16 @@ export const CounterSection = defineComponent({
8
8
  setup(props, { emit }) {
9
9
  const showCounter = signal(true)
10
10
  inspect(showCounter)
11
-
11
+
12
12
  return {
13
13
  showCounter,
14
14
  get title() { return props.pageTitle },
15
15
  toggleCounter: () => showCounter(!showCounter()),
16
-
17
- // 🔄 Re-emit handlers - forward events from Counter to parent
16
+
18
17
  handleCounterChange: (value) => emit('counter-change', value),
19
18
  handleCounterReset: () => emit('counter-reset'),
20
19
  handleCustomEvent: (count, multiplier) => emit('custom-event', count, multiplier),
21
-
20
+
22
21
  template: `
23
22
  <div style="margin-top: 30px; border-top: 1px solid #333; padding-top: 20px;">
24
23
  <h3>Counter Section</h3>
package/app/main.js CHANGED
@@ -1,62 +1,29 @@
1
- import { createRouter, mountOutlet, defineAsyncComponent } from '../framework/index.js'
2
- import { Loading } from './components/Loading.js'
3
-
4
- directive('focus', {
5
- mounted(el) {
6
- el.focus()
7
- }
8
- })
9
-
10
- directive('highlight', {
11
- mounted(el, binding) {
12
- el.style.backgroundColor = binding.value || '#ffff0033'
13
- el.style.transition = 'background-color 0.3s'
14
- },
15
- updated(el, binding) {
16
- el.style.backgroundColor = binding.value || '#ffff0033'
17
- }
18
- })
19
-
20
- const routes = [
21
- {
22
- path: '/',
23
- component: defineAsyncComponent({
24
- loader: () => import('./routes/Home.js'),
25
- loadingComponent: Loading
26
- })
27
- },
28
- {
29
- path: '/about',
30
- component: defineAsyncComponent({
31
- loader: () => import('./routes/About.js'),
32
- loadingComponent: Loading
33
- })
34
- },
35
- {
36
- path: '/test-for',
37
- component: defineAsyncComponent({
38
- loader: () => import('./routes/TestFor.js'),
39
- loadingComponent: Loading
40
- })
41
- },
42
- {
43
- path: '/dynamic',
44
- component: defineAsyncComponent({
45
- loader: () => import('./routes/TestDynamic.js'),
46
- loadingComponent: Loading
47
- })
48
- },
49
- {
50
- path: '/composables',
51
- component: defineAsyncComponent({
52
- loader: () => import('./routes/TestComposables.js'),
53
- loadingComponent: Loading
54
- })
55
- },
56
- ]
57
-
58
- createRouter(routes)
59
-
60
- const outlet = document.getElementById('app')
61
- if (!outlet) throw new Error('[app] #app element not found in DOM')
62
- mountOutlet(outlet)
1
+ import { createRouter, mountOutlet, defineAsyncComponent, generateRoutes } from '../framework/index.js'
2
+ import { Loading } from './components/Loading.js'
3
+
4
+ directive('focus', {
5
+ mounted(el) {
6
+ el.focus()
7
+ }
8
+ })
9
+
10
+ directive('highlight', {
11
+ mounted(el, binding) {
12
+ el.style.backgroundColor = binding.value || '#ffff0033'
13
+ el.style.transition = 'background-color 0.3s'
14
+ },
15
+ updated(el, binding) {
16
+ el.style.backgroundColor = binding.value || '#ffff0033'
17
+ }
18
+ })
19
+
20
+ const pages = import.meta.glob('./pages/**/*.{js,ts}')
21
+ const routes = generateRoutes(pages, {
22
+ loadingComponent: Loading
23
+ })
24
+
25
+ createRouter(routes)
26
+
27
+ const outlet = document.getElementById('app')
28
+ if (!outlet) throw new Error('[app] #app element not found in DOM')
29
+ mountOutlet(outlet)
package/app/main.ts CHANGED
@@ -1,63 +1,72 @@
1
- import { createRouter, mountOutlet, defineAsyncComponent } from '../framework/index.js'
2
- import type { Route } from '../framework/types/index.js'
3
- import { Loading } from './components/Loading.js'
4
-
5
- directive('focus', {
6
- mounted(el) {
7
- el.focus()
8
- }
9
- })
10
-
11
- directive('highlight', {
12
- mounted(el, binding) {
13
- el.style.backgroundColor = binding.value || '#ffff0033'
14
- el.style.transition = 'background-color 0.3s'
15
- },
16
- updated(el, binding) {
17
- el.style.backgroundColor = binding.value || '#ffff0033'
18
- }
19
- })
20
-
21
- const routes: Route[] = [
22
- {
23
- path: '/',
24
- component: defineAsyncComponent({
25
- loader: () => import('./routes/Home.ts'),
26
- loadingComponent: Loading
27
- })
28
- },
29
- {
30
- path: '/about',
31
- component: defineAsyncComponent({
32
- loader: () => import('./routes/About.ts'),
33
- loadingComponent: Loading
34
- })
35
- },
36
- {
37
- path: '/test-for',
38
- component: defineAsyncComponent({
39
- loader: () => import('./routes/TestFor.ts'),
40
- loadingComponent: Loading
41
- })
42
- },
43
- {
44
- path: '/dynamic',
45
- component: defineAsyncComponent({
46
- loader: () => import('./routes/TestDynamic.ts'),
47
- loadingComponent: Loading
48
- })
49
- },
50
- {
51
- path: '/composables',
52
- component: defineAsyncComponent({
53
- loader: () => import('./routes/TestComposables.ts'),
54
- loadingComponent: Loading
55
- })
56
- },
57
- ]
58
-
59
- createRouter(routes)
60
-
61
- const outlet = document.getElementById('app')
62
- if (!outlet) throw new Error('[app] #app element not found in DOM')
63
- mountOutlet(outlet)
1
+ import { createRouter, mountOutlet, generateRoutes } from '../framework/index.js'
2
+
3
+ import { Loading } from './components/Loading.js'
4
+
5
+ import { AuthRoutes } from './routes/AuthRoutes.js'
6
+
7
+
8
+
9
+ directive('focus', {
10
+
11
+ mounted(el) {
12
+
13
+ el.focus()
14
+
15
+ }
16
+
17
+ })
18
+
19
+
20
+
21
+ directive('highlight', {
22
+
23
+ mounted(el, binding) {
24
+
25
+ el.style.backgroundColor = binding.value || '#ffff0033'
26
+
27
+ el.style.transition = 'background-color 0.3s'
28
+
29
+ },
30
+
31
+ updated(el, binding) {
32
+
33
+ el.style.backgroundColor = binding.value || '#ffff0033'
34
+
35
+ }
36
+
37
+ })
38
+
39
+
40
+
41
+ const pages = import.meta.glob('./pages/**/*.{js,ts}')
42
+
43
+ const routes = generateRoutes(pages, {
44
+
45
+ loadingComponent: Loading
46
+
47
+ })
48
+
49
+
50
+
51
+ // Add manual route with array paths - component won't re-render when switching between /login and /register
52
+
53
+ routes.push({
54
+
55
+ path: ['/login', '/register'],
56
+
57
+ component: AuthRoutes
58
+
59
+ })
60
+
61
+
62
+
63
+ createRouter(routes)
64
+
65
+
66
+
67
+ const outlet = document.getElementById('app')
68
+
69
+ if (!outlet) throw new Error('[app] #app element not found in DOM')
70
+
71
+ mountOutlet(outlet)
72
+
@@ -0,0 +1,16 @@
1
+ import { navigate } from '../../framework/index.js'
2
+
3
+ export const NotFound = defineComponent({
4
+ setup() {
5
+ return {
6
+ navigate,
7
+ template: `
8
+ <div class="page">
9
+ <h1 style="color: #ff6b6b;">404 - Page Not Found</h1>
10
+ <p>The requested route does not exist.</p>
11
+ <button @click="navigate('/')" class="primary-btn">Go Home</button>
12
+ </div>
13
+ `
14
+ }
15
+ }
16
+ })
@@ -0,0 +1,35 @@
1
+ import { currentRoute, navigate } from '../../framework/index.js'
2
+
3
+ export const WildcardDemo = defineComponent({
4
+ setup() {
5
+ const path = currentRoute
6
+
7
+ return {
8
+ path,
9
+ navigate,
10
+ template: `
11
+ <div class="page">
12
+ <h1 style="color: #f59e0b;">🎯 Wildcard Match!</h1>
13
+ <p>This route matched via wildcard <code>path: '*'</code></p>
14
+
15
+ <div class="demo-card">
16
+ <h2>Current Path</h2>
17
+ <code style="color: #f59e0b; font-size: 1.5rem;">{{ path }}</code>
18
+ </div>
19
+
20
+ <div class="demo-card">
21
+ <h2>Test Wildcard</h2>
22
+ <p>Any path works here:</p>
23
+ <div style="display: flex; gap: 10px; flex-wrap: wrap;">
24
+ <button @click="navigate('/random-123')" class="cmp-btn">/random-123</button>
25
+ <button @click="navigate('/test/abc')" class="cmp-btn">/test/abc</button>
26
+ <button @click="navigate('/deep/nested/path')" class="cmp-btn">/deep/nested/path</button>
27
+ </div>
28
+ </div>
29
+
30
+ <button @click="navigate('/')" class="primary-btn">Back Home</button>
31
+ </div>
32
+ `
33
+ }
34
+ }
35
+ })