zero-query 1.0.9 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +2 -0
- package/cli/args.js +33 -33
- package/cli/commands/build-api.js +443 -0
- package/cli/commands/build.js +254 -216
- package/cli/commands/bundle.js +1228 -1183
- package/cli/commands/create.js +137 -121
- package/cli/commands/dev/devtools/index.js +56 -56
- package/cli/commands/dev/devtools/js/components.js +49 -49
- package/cli/commands/dev/devtools/js/core.js +423 -423
- package/cli/commands/dev/devtools/js/elements.js +421 -421
- package/cli/commands/dev/devtools/js/network.js +166 -166
- package/cli/commands/dev/devtools/js/performance.js +73 -73
- package/cli/commands/dev/devtools/js/router.js +105 -105
- package/cli/commands/dev/devtools/js/source.js +132 -132
- package/cli/commands/dev/devtools/js/stats.js +35 -35
- package/cli/commands/dev/devtools/js/tabs.js +79 -79
- package/cli/commands/dev/devtools/panel.html +95 -95
- package/cli/commands/dev/devtools/styles.css +244 -244
- package/cli/commands/dev/index.js +107 -107
- package/cli/commands/dev/logger.js +75 -75
- package/cli/commands/dev/overlay.js +858 -858
- package/cli/commands/dev/server.js +220 -167
- package/cli/commands/dev/validator.js +94 -94
- package/cli/commands/dev/watcher.js +172 -172
- package/cli/help.js +114 -112
- package/cli/index.js +52 -52
- package/cli/scaffold/default/LICENSE +21 -21
- package/cli/scaffold/default/app/app.js +207 -207
- package/cli/scaffold/default/app/components/about.js +201 -201
- package/cli/scaffold/default/app/components/api-demo.js +143 -143
- package/cli/scaffold/default/app/components/contact-card.js +231 -231
- package/cli/scaffold/default/app/components/contacts/contacts.css +706 -706
- package/cli/scaffold/default/app/components/contacts/contacts.html +200 -200
- package/cli/scaffold/default/app/components/contacts/contacts.js +196 -196
- package/cli/scaffold/default/app/components/counter.js +127 -127
- package/cli/scaffold/default/app/components/home.js +249 -249
- package/cli/scaffold/default/app/components/not-found.js +16 -16
- package/cli/scaffold/default/app/components/playground/playground.css +115 -115
- package/cli/scaffold/default/app/components/playground/playground.html +161 -161
- package/cli/scaffold/default/app/components/playground/playground.js +116 -116
- package/cli/scaffold/default/app/components/todos.js +225 -225
- package/cli/scaffold/default/app/components/toolkit/toolkit.css +97 -97
- package/cli/scaffold/default/app/components/toolkit/toolkit.html +146 -146
- package/cli/scaffold/default/app/components/toolkit/toolkit.js +280 -280
- package/cli/scaffold/default/app/routes.js +15 -15
- package/cli/scaffold/default/app/store.js +101 -101
- package/cli/scaffold/default/global.css +552 -552
- package/cli/scaffold/default/index.html +99 -99
- package/cli/scaffold/minimal/app/app.js +85 -85
- package/cli/scaffold/minimal/app/components/about.js +68 -68
- package/cli/scaffold/minimal/app/components/counter.js +122 -122
- package/cli/scaffold/minimal/app/components/home.js +68 -68
- package/cli/scaffold/minimal/app/components/not-found.js +16 -16
- package/cli/scaffold/minimal/app/routes.js +9 -9
- package/cli/scaffold/minimal/app/store.js +36 -36
- package/cli/scaffold/minimal/global.css +300 -300
- package/cli/scaffold/minimal/index.html +44 -44
- package/cli/scaffold/ssr/app/app.js +41 -41
- package/cli/scaffold/ssr/app/components/about.js +55 -55
- package/cli/scaffold/ssr/app/components/blog/index.js +65 -65
- package/cli/scaffold/ssr/app/components/blog/post.js +86 -86
- package/cli/scaffold/ssr/app/components/home.js +37 -37
- package/cli/scaffold/ssr/app/components/not-found.js +15 -15
- package/cli/scaffold/ssr/app/routes.js +8 -8
- package/cli/scaffold/ssr/global.css +228 -228
- package/cli/scaffold/ssr/index.html +37 -37
- package/cli/scaffold/ssr/package.json +8 -8
- package/cli/scaffold/ssr/server/data/posts.js +144 -144
- package/cli/scaffold/ssr/server/index.js +213 -213
- package/cli/scaffold/webrtc/app/app.js +11 -0
- package/cli/scaffold/webrtc/app/components/video-room.js +295 -0
- package/cli/scaffold/webrtc/app/lib/room.js +252 -0
- package/cli/scaffold/webrtc/assets/.gitkeep +0 -0
- package/cli/scaffold/webrtc/global.css +250 -0
- package/cli/scaffold/webrtc/index.html +21 -0
- package/cli/utils.js +305 -287
- package/dist/API.md +7264 -0
- package/dist/zquery.dist.zip +0 -0
- package/dist/zquery.js +10313 -6252
- package/dist/zquery.min.js +8 -601
- package/index.d.ts +570 -365
- package/index.js +311 -232
- package/package.json +76 -69
- package/src/component.js +1709 -1454
- package/src/core.js +921 -921
- package/src/diff.js +497 -497
- package/src/errors.js +209 -209
- package/src/expression.js +922 -922
- package/src/http.js +242 -242
- package/src/package.json +1 -1
- package/src/reactive.js +255 -254
- package/src/router.js +843 -773
- package/src/ssr.js +418 -418
- package/src/store.js +318 -272
- package/src/utils.js +515 -515
- package/src/webrtc/e2ee.js +351 -0
- package/src/webrtc/errors.js +116 -0
- package/src/webrtc/ice.js +301 -0
- package/src/webrtc/index.js +131 -0
- package/src/webrtc/joinToken.js +119 -0
- package/src/webrtc/observe.js +172 -0
- package/src/webrtc/peer.js +351 -0
- package/src/webrtc/reactive.js +268 -0
- package/src/webrtc/room.js +625 -0
- package/src/webrtc/sdp.js +302 -0
- package/src/webrtc/sfu/index.js +43 -0
- package/src/webrtc/sfu/livekit.js +131 -0
- package/src/webrtc/sfu/mediasoup.js +150 -0
- package/src/webrtc/signaling.js +373 -0
- package/src/webrtc/turn.js +237 -0
- package/tests/_helpers/webrtcFakes.js +289 -0
- package/tests/audit.test.js +4158 -4158
- package/tests/cli.test.js +1136 -1023
- package/tests/compare.test.js +497 -0
- package/tests/component.test.js +3969 -3938
- package/tests/core.test.js +1910 -1910
- package/tests/dev-server.test.js +489 -0
- package/tests/diff.test.js +1416 -1416
- package/tests/docs.test.js +1664 -0
- package/tests/electron-features.test.js +864 -0
- package/tests/errors.test.js +619 -619
- package/tests/expression.test.js +1056 -1056
- package/tests/http.test.js +648 -648
- package/tests/reactive.test.js +819 -819
- package/tests/router.test.js +2327 -2327
- package/tests/ssr.test.js +870 -870
- package/tests/store.test.js +830 -830
- package/tests/test-minifier.js +153 -153
- package/tests/test-ssr.js +27 -27
- package/tests/utils.test.js +1377 -1377
- package/tests/webrtc/e2ee.test.js +283 -0
- package/tests/webrtc/ice.test.js +202 -0
- package/tests/webrtc/joinToken.test.js +89 -0
- package/tests/webrtc/observe.test.js +111 -0
- package/tests/webrtc/peer.test.js +373 -0
- package/tests/webrtc/reactive.test.js +235 -0
- package/tests/webrtc/room.test.js +406 -0
- package/tests/webrtc/sdp.test.js +151 -0
- package/tests/webrtc/sfu-livekit.test.js +119 -0
- package/tests/webrtc/sfu.test.js +160 -0
- package/tests/webrtc/signaling.test.js +251 -0
- package/tests/webrtc/turn.test.js +256 -0
- package/types/collection.d.ts +383 -383
- package/types/component.d.ts +186 -186
- package/types/errors.d.ts +135 -135
- package/types/http.d.ts +92 -92
- package/types/misc.d.ts +201 -201
- package/types/reactive.d.ts +98 -98
- package/types/router.d.ts +190 -190
- package/types/ssr.d.ts +102 -102
- package/types/store.d.ts +146 -145
- package/types/utils.d.ts +245 -245
- package/types/webrtc.d.ts +653 -0
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
// counter.js - Interactive counter
|
|
2
|
-
//
|
|
3
|
-
// Features used:
|
|
4
|
-
// $.getStore / store.subscribe - shared state + live re-render
|
|
5
|
-
// @click / z-model + z-number - events + two-way binding
|
|
6
|
-
// z-if / z-for / z-key - conditional & keyed list rendering
|
|
7
|
-
|
|
8
|
-
$.component('counter-page', {
|
|
9
|
-
styles: `
|
|
10
|
-
.ctr-display { padding: 2rem 0 1.25rem; text-align: center; }
|
|
11
|
-
.ctr-num { font-size: 4rem; font-weight: 800; font-variant-numeric: tabular-nums;
|
|
12
|
-
color: var(--accent); transition: color .2s; line-height: 1; }
|
|
13
|
-
.ctr-num.negative { color: var(--danger); }
|
|
14
|
-
.ctr-label { font-size: .82rem; color: var(--text-muted); margin-top: .35rem; }
|
|
15
|
-
.ctr-actions { display: flex; justify-content: center; gap: .65rem;
|
|
16
|
-
margin-bottom: 1.5rem; }
|
|
17
|
-
.ctr-actions .btn { min-width: 120px; justify-content: center; }
|
|
18
|
-
.ctr-config { display: flex; align-items: center; justify-content: center; gap: 1.25rem;
|
|
19
|
-
padding-top: 1.15rem; border-top: 1px solid var(--border); }
|
|
20
|
-
.ctr-config label { display: flex; align-items: center; gap: .5rem;
|
|
21
|
-
color: var(--text-muted); font-size: .88rem; }
|
|
22
|
-
.ctr-config .input-sm { width: 65px; text-align: center; }
|
|
23
|
-
.ctr-hist { display: flex; flex-wrap: wrap; gap: .4rem; }
|
|
24
|
-
.ctr-hist-item { display: inline-flex; align-items: center; gap: .3rem;
|
|
25
|
-
padding: .3rem .65rem; border-radius: var(--radius);
|
|
26
|
-
background: var(--bg-hover); border: 1px solid var(--border);
|
|
27
|
-
font-size: .82rem; font-variant-numeric: tabular-nums; }
|
|
28
|
-
.ctr-hist-item:last-child { border-color: var(--accent); background: rgba(88,166,255,.06); }
|
|
29
|
-
.ctr-hist-op { color: var(--text-muted); font-weight: 500; }
|
|
30
|
-
.ctr-hist-val { color: var(--accent); font-weight: 600; }
|
|
31
|
-
|
|
32
|
-
@media (max-width: 768px) {
|
|
33
|
-
.ctr-num { font-size: 2.75rem; }
|
|
34
|
-
.ctr-actions { gap: .5rem; }
|
|
35
|
-
.ctr-actions .btn { min-width: 100px; }
|
|
36
|
-
.ctr-config { flex-wrap: wrap; gap: .75rem; }
|
|
37
|
-
}
|
|
38
|
-
@media (max-width: 480px) {
|
|
39
|
-
.ctr-num { font-size: 2.25rem; }
|
|
40
|
-
.ctr-actions .btn { min-width: 0; flex: 1; }
|
|
41
|
-
}
|
|
42
|
-
`,
|
|
43
|
-
|
|
44
|
-
state: () => ({
|
|
45
|
-
history: [],
|
|
46
|
-
}),
|
|
47
|
-
|
|
48
|
-
mounted() {
|
|
49
|
-
this._unsub = $.getStore('main').subscribe(() => this.setState({}));
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
destroyed() {
|
|
53
|
-
if (this._unsub) this._unsub();
|
|
54
|
-
},
|
|
55
|
-
|
|
56
|
-
increment() {
|
|
57
|
-
const store = $.getStore('main');
|
|
58
|
-
store.dispatch('increment');
|
|
59
|
-
this._pushHistory('+', store.state.step, store.state.count);
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
decrement() {
|
|
63
|
-
const store = $.getStore('main');
|
|
64
|
-
store.dispatch('decrement');
|
|
65
|
-
this._pushHistory('-', store.state.step, store.state.count);
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
setStep(e) {
|
|
69
|
-
$.getStore('main').dispatch('setStep', Number(e.target.value));
|
|
70
|
-
},
|
|
71
|
-
|
|
72
|
-
_pushHistory(action, value, result) {
|
|
73
|
-
const raw = this.state.history.__raw || this.state.history;
|
|
74
|
-
const next = [...raw, { id: Date.now(), action, value, result }];
|
|
75
|
-
this.state.history = next.length > 8 ? next.slice(-8) : next;
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
reset() {
|
|
79
|
-
$.getStore('main').dispatch('reset');
|
|
80
|
-
this.state.history = [];
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
render() {
|
|
84
|
-
const { count, step } = $.getStore('main').state;
|
|
85
|
-
|
|
86
|
-
return `
|
|
87
|
-
<div class="page-header">
|
|
88
|
-
<h1>Counter</h1>
|
|
89
|
-
<p class="subtitle">Reactive <code>store</code>, <code>subscribe</code>, <code>dispatch</code>, and <code>z-for</code>.</p>
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
<div class="card">
|
|
93
|
-
<div class="ctr-display">
|
|
94
|
-
<div class="ctr-num ${count < 0 ? 'negative' : ''}">${count}</div>
|
|
95
|
-
<div class="ctr-label">current value${step !== 1 ? ` · step ${step}` : ''}</div>
|
|
96
|
-
</div>
|
|
97
|
-
|
|
98
|
-
<div class="ctr-actions">
|
|
99
|
-
<button class="btn btn-outline" @click="decrement">- Subtract</button>
|
|
100
|
-
<button class="btn btn-primary" @click="increment">+ Add</button>
|
|
101
|
-
</div>
|
|
102
|
-
|
|
103
|
-
<div class="ctr-config">
|
|
104
|
-
<label>Step size
|
|
105
|
-
<input type="number" value="${step}" @input="setStep" min="1" max="100" class="input input-sm" />
|
|
106
|
-
</label>
|
|
107
|
-
<button class="btn btn-ghost btn-sm" @click="reset">Reset</button>
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
|
|
111
|
-
<div class="card" z-if="history.length > 0">
|
|
112
|
-
<h3>History <small style="color:var(--text-muted);font-weight:400;font-size:.85rem;">${this.state.history.length} entries</small></h3>
|
|
113
|
-
<div class="ctr-hist">
|
|
114
|
-
<span z-for="e in history" z-key="{{e.id}}" class="ctr-hist-item">
|
|
115
|
-
<span class="ctr-hist-op">{{e.action}}{{e.value}}</span>
|
|
116
|
-
<span class="ctr-hist-val">→ {{e.result}}</span>
|
|
117
|
-
</span>
|
|
118
|
-
</div>
|
|
119
|
-
</div>
|
|
120
|
-
`;
|
|
121
|
-
}
|
|
122
|
-
});
|
|
1
|
+
// counter.js - Interactive counter
|
|
2
|
+
//
|
|
3
|
+
// Features used:
|
|
4
|
+
// $.getStore / store.subscribe - shared state + live re-render
|
|
5
|
+
// @click / z-model + z-number - events + two-way binding
|
|
6
|
+
// z-if / z-for / z-key - conditional & keyed list rendering
|
|
7
|
+
|
|
8
|
+
$.component('counter-page', {
|
|
9
|
+
styles: `
|
|
10
|
+
.ctr-display { padding: 2rem 0 1.25rem; text-align: center; }
|
|
11
|
+
.ctr-num { font-size: 4rem; font-weight: 800; font-variant-numeric: tabular-nums;
|
|
12
|
+
color: var(--accent); transition: color .2s; line-height: 1; }
|
|
13
|
+
.ctr-num.negative { color: var(--danger); }
|
|
14
|
+
.ctr-label { font-size: .82rem; color: var(--text-muted); margin-top: .35rem; }
|
|
15
|
+
.ctr-actions { display: flex; justify-content: center; gap: .65rem;
|
|
16
|
+
margin-bottom: 1.5rem; }
|
|
17
|
+
.ctr-actions .btn { min-width: 120px; justify-content: center; }
|
|
18
|
+
.ctr-config { display: flex; align-items: center; justify-content: center; gap: 1.25rem;
|
|
19
|
+
padding-top: 1.15rem; border-top: 1px solid var(--border); }
|
|
20
|
+
.ctr-config label { display: flex; align-items: center; gap: .5rem;
|
|
21
|
+
color: var(--text-muted); font-size: .88rem; }
|
|
22
|
+
.ctr-config .input-sm { width: 65px; text-align: center; }
|
|
23
|
+
.ctr-hist { display: flex; flex-wrap: wrap; gap: .4rem; }
|
|
24
|
+
.ctr-hist-item { display: inline-flex; align-items: center; gap: .3rem;
|
|
25
|
+
padding: .3rem .65rem; border-radius: var(--radius);
|
|
26
|
+
background: var(--bg-hover); border: 1px solid var(--border);
|
|
27
|
+
font-size: .82rem; font-variant-numeric: tabular-nums; }
|
|
28
|
+
.ctr-hist-item:last-child { border-color: var(--accent); background: rgba(88,166,255,.06); }
|
|
29
|
+
.ctr-hist-op { color: var(--text-muted); font-weight: 500; }
|
|
30
|
+
.ctr-hist-val { color: var(--accent); font-weight: 600; }
|
|
31
|
+
|
|
32
|
+
@media (max-width: 768px) {
|
|
33
|
+
.ctr-num { font-size: 2.75rem; }
|
|
34
|
+
.ctr-actions { gap: .5rem; }
|
|
35
|
+
.ctr-actions .btn { min-width: 100px; }
|
|
36
|
+
.ctr-config { flex-wrap: wrap; gap: .75rem; }
|
|
37
|
+
}
|
|
38
|
+
@media (max-width: 480px) {
|
|
39
|
+
.ctr-num { font-size: 2.25rem; }
|
|
40
|
+
.ctr-actions .btn { min-width: 0; flex: 1; }
|
|
41
|
+
}
|
|
42
|
+
`,
|
|
43
|
+
|
|
44
|
+
state: () => ({
|
|
45
|
+
history: [],
|
|
46
|
+
}),
|
|
47
|
+
|
|
48
|
+
mounted() {
|
|
49
|
+
this._unsub = $.getStore('main').subscribe(() => this.setState({}));
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
destroyed() {
|
|
53
|
+
if (this._unsub) this._unsub();
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
increment() {
|
|
57
|
+
const store = $.getStore('main');
|
|
58
|
+
store.dispatch('increment');
|
|
59
|
+
this._pushHistory('+', store.state.step, store.state.count);
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
decrement() {
|
|
63
|
+
const store = $.getStore('main');
|
|
64
|
+
store.dispatch('decrement');
|
|
65
|
+
this._pushHistory('-', store.state.step, store.state.count);
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
setStep(e) {
|
|
69
|
+
$.getStore('main').dispatch('setStep', Number(e.target.value));
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
_pushHistory(action, value, result) {
|
|
73
|
+
const raw = this.state.history.__raw || this.state.history;
|
|
74
|
+
const next = [...raw, { id: Date.now(), action, value, result }];
|
|
75
|
+
this.state.history = next.length > 8 ? next.slice(-8) : next;
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
reset() {
|
|
79
|
+
$.getStore('main').dispatch('reset');
|
|
80
|
+
this.state.history = [];
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
render() {
|
|
84
|
+
const { count, step } = $.getStore('main').state;
|
|
85
|
+
|
|
86
|
+
return `
|
|
87
|
+
<div class="page-header">
|
|
88
|
+
<h1>Counter</h1>
|
|
89
|
+
<p class="subtitle">Reactive <code>store</code>, <code>subscribe</code>, <code>dispatch</code>, and <code>z-for</code>.</p>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<div class="card">
|
|
93
|
+
<div class="ctr-display">
|
|
94
|
+
<div class="ctr-num ${count < 0 ? 'negative' : ''}">${count}</div>
|
|
95
|
+
<div class="ctr-label">current value${step !== 1 ? ` · step ${step}` : ''}</div>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div class="ctr-actions">
|
|
99
|
+
<button class="btn btn-outline" @click="decrement">- Subtract</button>
|
|
100
|
+
<button class="btn btn-primary" @click="increment">+ Add</button>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div class="ctr-config">
|
|
104
|
+
<label>Step size
|
|
105
|
+
<input type="number" value="${step}" @input="setStep" min="1" max="100" class="input input-sm" />
|
|
106
|
+
</label>
|
|
107
|
+
<button class="btn btn-ghost btn-sm" @click="reset">Reset</button>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="card" z-if="history.length > 0">
|
|
112
|
+
<h3>History <small style="color:var(--text-muted);font-weight:400;font-size:.85rem;">${this.state.history.length} entries</small></h3>
|
|
113
|
+
<div class="ctr-hist">
|
|
114
|
+
<span z-for="e in history" z-key="{{e.id}}" class="ctr-hist-item">
|
|
115
|
+
<span class="ctr-hist-op">{{e.action}}{{e.value}}</span>
|
|
116
|
+
<span class="ctr-hist-val">→ {{e.result}}</span>
|
|
117
|
+
</span>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
`;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
// home.js - Landing page
|
|
2
|
-
//
|
|
3
|
-
// Features used:
|
|
4
|
-
// $.component - define a component
|
|
5
|
-
// $.getStore - read/dispatch global store
|
|
6
|
-
// store.subscribe - re-render on store changes
|
|
7
|
-
// @click / z-model - event binding + two-way input
|
|
8
|
-
|
|
9
|
-
$.component('home-page', {
|
|
10
|
-
state: () => ({
|
|
11
|
-
greeting: '',
|
|
12
|
-
}),
|
|
13
|
-
|
|
14
|
-
mounted() {
|
|
15
|
-
const hour = new Date().getHours();
|
|
16
|
-
this.state.greeting =
|
|
17
|
-
hour < 12 ? 'Good morning' :
|
|
18
|
-
hour < 18 ? 'Good afternoon' : 'Good evening';
|
|
19
|
-
|
|
20
|
-
this._unsub = $.getStore('main').subscribe(() => this.setState({}));
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
destroyed() {
|
|
24
|
-
if (this._unsub) this._unsub();
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
increment() { $.getStore('main').dispatch('increment'); },
|
|
28
|
-
decrement() { $.getStore('main').dispatch('decrement'); },
|
|
29
|
-
reset() { $.getStore('main').dispatch('reset'); },
|
|
30
|
-
setStep(e) { $.getStore('main').dispatch('setStep', Number(e.target.value)); },
|
|
31
|
-
|
|
32
|
-
render() {
|
|
33
|
-
const { count, step } = $.getStore('main').state;
|
|
34
|
-
|
|
35
|
-
return `
|
|
36
|
-
<div class="page-header">
|
|
37
|
-
<h1>{{greeting}} 👋</h1>
|
|
38
|
-
<p class="subtitle">Welcome to your new zQuery project.</p>
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<div class="card">
|
|
42
|
-
<h3>Getting Started</h3>
|
|
43
|
-
<p>
|
|
44
|
-
This is the <strong>minimal</strong> scaffold - three pages, a global store,
|
|
45
|
-
and the router. Edit the files in <code>app/</code> to start building.
|
|
46
|
-
</p>
|
|
47
|
-
<p>
|
|
48
|
-
Run <code>npx zquery dev</code> for live-reload, or
|
|
49
|
-
<code>npx zquery bundle</code> when you're ready to ship.
|
|
50
|
-
</p>
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
<div class="card">
|
|
54
|
-
<h3>Global Store</h3>
|
|
55
|
-
<p>The counter from <a z-link="/counter">Counter</a> is backed by <code>$.store</code> - its value persists across pages:</p>
|
|
56
|
-
<div style="display:flex;align-items:center;gap:.75rem;margin-top:.75rem;">
|
|
57
|
-
<button class="btn btn-outline btn-sm" @click="decrement">-</button>
|
|
58
|
-
<span style="font-size:1.25rem;font-weight:700;color:var(--accent);min-width:2rem;text-align:center;">${count}</span>
|
|
59
|
-
<button class="btn btn-primary btn-sm" @click="increment">+</button>
|
|
60
|
-
<button class="btn btn-outline btn-sm" @click="reset" style="margin-left:.5rem;">Reset</button>
|
|
61
|
-
<label style="display:flex;align-items:center;gap:.4rem;margin-left:.5rem;font-size:.85rem;color:var(--text-muted);">
|
|
62
|
-
Step <input type="number" value="${step}" @input="setStep" min="1" max="100" class="input input-sm" style="width:55px;text-align:center;" />
|
|
63
|
-
</label>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
`;
|
|
67
|
-
},
|
|
68
|
-
});
|
|
1
|
+
// home.js - Landing page
|
|
2
|
+
//
|
|
3
|
+
// Features used:
|
|
4
|
+
// $.component - define a component
|
|
5
|
+
// $.getStore - read/dispatch global store
|
|
6
|
+
// store.subscribe - re-render on store changes
|
|
7
|
+
// @click / z-model - event binding + two-way input
|
|
8
|
+
|
|
9
|
+
$.component('home-page', {
|
|
10
|
+
state: () => ({
|
|
11
|
+
greeting: '',
|
|
12
|
+
}),
|
|
13
|
+
|
|
14
|
+
mounted() {
|
|
15
|
+
const hour = new Date().getHours();
|
|
16
|
+
this.state.greeting =
|
|
17
|
+
hour < 12 ? 'Good morning' :
|
|
18
|
+
hour < 18 ? 'Good afternoon' : 'Good evening';
|
|
19
|
+
|
|
20
|
+
this._unsub = $.getStore('main').subscribe(() => this.setState({}));
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
destroyed() {
|
|
24
|
+
if (this._unsub) this._unsub();
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
increment() { $.getStore('main').dispatch('increment'); },
|
|
28
|
+
decrement() { $.getStore('main').dispatch('decrement'); },
|
|
29
|
+
reset() { $.getStore('main').dispatch('reset'); },
|
|
30
|
+
setStep(e) { $.getStore('main').dispatch('setStep', Number(e.target.value)); },
|
|
31
|
+
|
|
32
|
+
render() {
|
|
33
|
+
const { count, step } = $.getStore('main').state;
|
|
34
|
+
|
|
35
|
+
return `
|
|
36
|
+
<div class="page-header">
|
|
37
|
+
<h1>{{greeting}} 👋</h1>
|
|
38
|
+
<p class="subtitle">Welcome to your new zQuery project.</p>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="card">
|
|
42
|
+
<h3>Getting Started</h3>
|
|
43
|
+
<p>
|
|
44
|
+
This is the <strong>minimal</strong> scaffold - three pages, a global store,
|
|
45
|
+
and the router. Edit the files in <code>app/</code> to start building.
|
|
46
|
+
</p>
|
|
47
|
+
<p>
|
|
48
|
+
Run <code>npx zquery dev</code> for live-reload, or
|
|
49
|
+
<code>npx zquery bundle</code> when you're ready to ship.
|
|
50
|
+
</p>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div class="card">
|
|
54
|
+
<h3>Global Store</h3>
|
|
55
|
+
<p>The counter from <a z-link="/counter">Counter</a> is backed by <code>$.store</code> - its value persists across pages:</p>
|
|
56
|
+
<div style="display:flex;align-items:center;gap:.75rem;margin-top:.75rem;">
|
|
57
|
+
<button class="btn btn-outline btn-sm" @click="decrement">-</button>
|
|
58
|
+
<span style="font-size:1.25rem;font-weight:700;color:var(--accent);min-width:2rem;text-align:center;">${count}</span>
|
|
59
|
+
<button class="btn btn-primary btn-sm" @click="increment">+</button>
|
|
60
|
+
<button class="btn btn-outline btn-sm" @click="reset" style="margin-left:.5rem;">Reset</button>
|
|
61
|
+
<label style="display:flex;align-items:center;gap:.4rem;margin-left:.5rem;font-size:.85rem;color:var(--text-muted);">
|
|
62
|
+
Step <input type="number" value="${step}" @input="setStep" min="1" max="100" class="input input-sm" style="width:55px;text-align:center;" />
|
|
63
|
+
</label>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
`;
|
|
67
|
+
},
|
|
68
|
+
});
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
// not-found.js - 404 fallback page
|
|
2
|
-
//
|
|
3
|
-
// Uses $.getRouter() to display the unmatched path.
|
|
4
|
-
|
|
5
|
-
$.component('not-found', {
|
|
6
|
-
render() {
|
|
7
|
-
const router = $.getRouter();
|
|
8
|
-
return `
|
|
9
|
-
<div class="page-header center">
|
|
10
|
-
<h1>404</h1>
|
|
11
|
-
<p class="subtitle">The page <code>${$.escapeHtml(router.current?.path || '')}</code> was not found.</p>
|
|
12
|
-
<a z-link="/" class="btn btn-primary">← Go Home</a>
|
|
13
|
-
</div>
|
|
14
|
-
`;
|
|
15
|
-
}
|
|
16
|
-
});
|
|
1
|
+
// not-found.js - 404 fallback page
|
|
2
|
+
//
|
|
3
|
+
// Uses $.getRouter() to display the unmatched path.
|
|
4
|
+
|
|
5
|
+
$.component('not-found', {
|
|
6
|
+
render() {
|
|
7
|
+
const router = $.getRouter();
|
|
8
|
+
return `
|
|
9
|
+
<div class="page-header center">
|
|
10
|
+
<h1>404</h1>
|
|
11
|
+
<p class="subtitle">The page <code>${$.escapeHtml(router.current?.path || '')}</code> was not found.</p>
|
|
12
|
+
<a z-link="/" class="btn btn-primary">← Go Home</a>
|
|
13
|
+
</div>
|
|
14
|
+
`;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// routes.js - Route definitions
|
|
2
|
-
//
|
|
3
|
-
// Maps URL paths to component tag names.
|
|
4
|
-
|
|
5
|
-
export const routes = [
|
|
6
|
-
{ path: '/', component: 'home-page' },
|
|
7
|
-
{ path: '/counter', component: 'counter-page' },
|
|
8
|
-
{ path: '/about', component: 'about-page' },
|
|
9
|
-
];
|
|
1
|
+
// routes.js - Route definitions
|
|
2
|
+
//
|
|
3
|
+
// Maps URL paths to component tag names.
|
|
4
|
+
|
|
5
|
+
export const routes = [
|
|
6
|
+
{ path: '/', component: 'home-page' },
|
|
7
|
+
{ path: '/counter', component: 'counter-page' },
|
|
8
|
+
{ path: '/about', component: 'about-page' },
|
|
9
|
+
];
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
// store.js - Global state management
|
|
2
|
-
//
|
|
3
|
-
// A simple centralized store. Any component can access it
|
|
4
|
-
// via $.getStore('main') and dispatch actions to update state.
|
|
5
|
-
|
|
6
|
-
export const store = $.store('main', {
|
|
7
|
-
state: {
|
|
8
|
-
count: 0,
|
|
9
|
-
step: 1,
|
|
10
|
-
},
|
|
11
|
-
|
|
12
|
-
actions: {
|
|
13
|
-
increment(state) {
|
|
14
|
-
state.count += state.step;
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
-
decrement(state) {
|
|
18
|
-
state.count -= state.step;
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
reset(state) {
|
|
22
|
-
state.count = 0;
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
setStep(state, value) {
|
|
26
|
-
state.step = Math.max(1, Math.min(100, value));
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
getters: {
|
|
31
|
-
isNegative: (state) => state.count < 0,
|
|
32
|
-
isPositive: (state) => state.count > 0,
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
debug: true,
|
|
36
|
-
});
|
|
1
|
+
// store.js - Global state management
|
|
2
|
+
//
|
|
3
|
+
// A simple centralized store. Any component can access it
|
|
4
|
+
// via $.getStore('main') and dispatch actions to update state.
|
|
5
|
+
|
|
6
|
+
export const store = $.store('main', {
|
|
7
|
+
state: {
|
|
8
|
+
count: 0,
|
|
9
|
+
step: 1,
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
actions: {
|
|
13
|
+
increment(state) {
|
|
14
|
+
state.count += state.step;
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
decrement(state) {
|
|
18
|
+
state.count -= state.step;
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
reset(state) {
|
|
22
|
+
state.count = 0;
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
setStep(state, value) {
|
|
26
|
+
state.step = Math.max(1, Math.min(100, value));
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
getters: {
|
|
31
|
+
isNegative: (state) => state.count < 0,
|
|
32
|
+
isPositive: (state) => state.count > 0,
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
debug: true,
|
|
36
|
+
});
|