jac-client 0.2.6__py3-none-any.whl → 0.2.11__py3-none-any.whl
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.
- jac_client/examples/all-in-one/{src/button.jac → button.jac} +4 -3
- jac_client/examples/all-in-one/components/CategoryFilter.jac +47 -0
- jac_client/examples/all-in-one/components/Header.jac +17 -0
- jac_client/examples/all-in-one/components/ProfitOverview.jac +64 -0
- jac_client/examples/all-in-one/components/Summary.jac +76 -0
- jac_client/examples/all-in-one/components/TransactionForm.jac +188 -0
- jac_client/examples/all-in-one/components/TransactionItem.jac +62 -0
- jac_client/examples/all-in-one/components/TransactionList.jac +44 -0
- jac_client/examples/all-in-one/components/button.jac +8 -0
- jac_client/examples/all-in-one/components/navigation.jac +126 -0
- jac_client/examples/all-in-one/constants/categories.jac +36 -0
- jac_client/examples/all-in-one/constants/clients.jac +12 -0
- jac_client/examples/all-in-one/context/BudgetContext.jac +31 -0
- jac_client/examples/all-in-one/hooks/useBudget.jac +122 -0
- jac_client/examples/all-in-one/hooks/useLocalStorage.jac +37 -0
- jac_client/examples/all-in-one/main.jac +542 -0
- jac_client/examples/all-in-one/pages/BudgetPlanner.jac +140 -0
- jac_client/examples/all-in-one/pages/FeaturesTest.jac +157 -0
- jac_client/examples/all-in-one/pages/LandingPage.jac +124 -0
- jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +65 -0
- jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +675 -0
- jac_client/examples/all-in-one/pages/loginPage.jac +127 -0
- jac_client/examples/all-in-one/pages/nestedDemo.jac +54 -0
- jac_client/examples/all-in-one/pages/notFound.jac +18 -0
- jac_client/examples/all-in-one/pages/signupPage.jac +127 -0
- jac_client/examples/all-in-one/utils/formatters.jac +49 -0
- jac_client/examples/asset-serving/css-with-image/main.jac +92 -0
- jac_client/examples/asset-serving/image-asset/main.jac +56 -0
- jac_client/examples/asset-serving/import-alias/main.jac +109 -0
- jac_client/examples/basic/main.jac +23 -0
- jac_client/examples/basic-auth/main.jac +363 -0
- jac_client/examples/basic-auth-with-router/main.jac +451 -0
- jac_client/examples/basic-full-stack/main.jac +362 -0
- jac_client/examples/css-styling/js-styling/main.jac +63 -0
- jac_client/examples/css-styling/material-ui/main.jac +122 -0
- jac_client/examples/css-styling/pure-css/main.jac +55 -0
- jac_client/examples/css-styling/sass-example/main.jac +55 -0
- jac_client/examples/css-styling/styled-components/main.jac +62 -0
- jac_client/examples/css-styling/tailwind-example/main.jac +74 -0
- jac_client/examples/full-stack-with-auth/main.jac +696 -0
- jac_client/examples/little-x/main.jac +681 -0
- jac_client/examples/little-x/src/submit-button.jac +15 -14
- jac_client/examples/nested-folders/nested-advance/main.jac +26 -0
- jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +4 -6
- jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +9 -13
- jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +29 -32
- jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +12 -18
- jac_client/examples/nested-folders/nested-basic/{src/app.jac → main.jac} +7 -5
- jac_client/examples/nested-folders/nested-basic/src/button.jac +4 -3
- jac_client/examples/nested-folders/nested-basic/src/components/button.jac +4 -3
- jac_client/examples/ts-support/main.jac +35 -0
- jac_client/examples/with-router/main.jac +286 -0
- jac_client/plugin/cli.jac +507 -470
- jac_client/plugin/client.jac +30 -12
- jac_client/plugin/client_runtime.cl.jac +25 -15
- jac_client/plugin/impl/client.impl.jac +126 -26
- jac_client/plugin/impl/client_runtime.impl.jac +182 -10
- jac_client/plugin/plugin_config.jac +216 -34
- jac_client/plugin/src/__init__.jac +0 -2
- jac_client/plugin/src/compiler.jac +2 -2
- jac_client/plugin/src/config_loader.jac +1 -0
- jac_client/plugin/src/desktop_config.jac +31 -0
- jac_client/plugin/src/impl/compiler.impl.jac +99 -30
- jac_client/plugin/src/impl/config_loader.impl.jac +8 -0
- jac_client/plugin/src/impl/desktop_config.impl.jac +191 -0
- jac_client/plugin/src/impl/jac_to_js.impl.jac +5 -1
- jac_client/plugin/src/impl/package_installer.impl.jac +20 -20
- jac_client/plugin/src/impl/vite_bundler.impl.jac +384 -144
- jac_client/plugin/src/package_installer.jac +1 -1
- jac_client/plugin/src/targets/desktop/sidecar/main.py +144 -0
- jac_client/plugin/src/targets/desktop_target.jac +37 -0
- jac_client/plugin/src/targets/impl/desktop_target.impl.jac +2347 -0
- jac_client/plugin/src/targets/impl/registry.impl.jac +64 -0
- jac_client/plugin/src/targets/impl/web_target.impl.jac +157 -0
- jac_client/plugin/src/targets/register.jac +21 -0
- jac_client/plugin/src/targets/registry.jac +87 -0
- jac_client/plugin/src/targets/web_target.jac +35 -0
- jac_client/plugin/src/vite_bundler.jac +15 -1
- jac_client/plugin/utils/__init__.jac +3 -0
- jac_client/plugin/utils/bun_installer.jac +16 -0
- jac_client/plugin/utils/impl/bun_installer.impl.jac +99 -0
- jac_client/templates/client.jacpack +72 -0
- jac_client/templates/fullstack.jacpack +61 -0
- jac_client/tests/conftest.py +110 -52
- jac_client/tests/fixtures/spawn_test/app.jac +64 -70
- jac_client/tests/fixtures/with-ts/app.jac +28 -28
- jac_client/tests/test_cli.py +280 -113
- jac_client/tests/test_e2e.py +232 -0
- jac_client/tests/test_helpers.py +58 -0
- jac_client/tests/test_it.py +325 -154
- jac_client/tests/test_it_desktop.py +891 -0
- {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/METADATA +20 -11
- jac_client-0.2.11.dist-info/RECORD +113 -0
- {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/WHEEL +1 -1
- jac_client/examples/all-in-one/src/app.jac +0 -841
- jac_client/examples/all-in-one/src/components/button.jac +0 -7
- jac_client/examples/asset-serving/css-with-image/src/app.jac +0 -88
- jac_client/examples/asset-serving/image-asset/src/app.jac +0 -55
- jac_client/examples/asset-serving/import-alias/src/app.jac +0 -111
- jac_client/examples/basic/src/app.jac +0 -21
- jac_client/examples/basic-auth/src/app.jac +0 -377
- jac_client/examples/basic-auth-with-router/src/app.jac +0 -464
- jac_client/examples/basic-full-stack/src/app.jac +0 -365
- jac_client/examples/css-styling/js-styling/src/app.jac +0 -84
- jac_client/examples/css-styling/material-ui/src/app.jac +0 -122
- jac_client/examples/css-styling/pure-css/src/app.jac +0 -64
- jac_client/examples/css-styling/sass-example/src/app.jac +0 -64
- jac_client/examples/css-styling/styled-components/src/app.jac +0 -71
- jac_client/examples/css-styling/tailwind-example/src/app.jac +0 -63
- jac_client/examples/full-stack-with-auth/src/app.jac +0 -722
- jac_client/examples/little-x/src/app.jac +0 -719
- jac_client/examples/nested-folders/nested-advance/src/app.jac +0 -35
- jac_client/examples/ts-support/src/app.jac +0 -35
- jac_client/examples/with-router/src/app.jac +0 -323
- jac_client/plugin/src/babel_processor.jac +0 -18
- jac_client/plugin/src/impl/babel_processor.impl.jac +0 -84
- jac_client-0.2.6.dist-info/RECORD +0 -74
- {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/entry_points.txt +0 -0
- {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/top_level.txt +0 -0
|
@@ -1,841 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Combined example: auth + routing + CSS styling + asset serving + nested folder imports
|
|
3
|
-
#
|
|
4
|
-
cl import from react { useState, useEffect, useRef }
|
|
5
|
-
cl import from "@jac-client/utils" {
|
|
6
|
-
Router,
|
|
7
|
-
Routes,
|
|
8
|
-
Route,
|
|
9
|
-
Link,
|
|
10
|
-
Navigate,
|
|
11
|
-
useNavigate,
|
|
12
|
-
useLocation,
|
|
13
|
-
jacSignup,
|
|
14
|
-
jacLogin,
|
|
15
|
-
jacLogout,
|
|
16
|
-
jacIsLoggedIn
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
# Pure CSS + asset-in-CSS example
|
|
20
|
-
cl import ".styles.css";
|
|
21
|
-
|
|
22
|
-
# Nested folder imports (same pattern as nested-basic/)
|
|
23
|
-
cl import from .components.button {
|
|
24
|
-
CustomButton
|
|
25
|
-
}
|
|
26
|
-
cl import from .button { CustomButtonRoot }
|
|
27
|
-
|
|
28
|
-
# TypeScript component import
|
|
29
|
-
cl import from ".components/Card.tsx" { Card }
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
# Basic backend walkers
|
|
33
|
-
#
|
|
34
|
-
node Todo {
|
|
35
|
-
has text: str,
|
|
36
|
-
done: bool = False;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
walker create_todo {
|
|
40
|
-
has text: str;
|
|
41
|
-
|
|
42
|
-
can create with `root entry {
|
|
43
|
-
new_todo = here ++> Todo(text=self.text);
|
|
44
|
-
report new_todo ;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
walker ping_server {
|
|
49
|
-
can ping with `root entry {
|
|
50
|
-
report "pong from backend!" ;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
walker get_server_message {
|
|
55
|
-
can info with `root entry {
|
|
56
|
-
report "hello from a basic walker!" ;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
cl {
|
|
61
|
-
# Login Page
|
|
62
|
-
def LoginPage -> any {
|
|
63
|
-
[username, setUsername] = useState("");
|
|
64
|
-
[password, setPassword] = useState("");
|
|
65
|
-
[error, setError] = useState("");
|
|
66
|
-
navigate = useNavigate();
|
|
67
|
-
|
|
68
|
-
async def handleLogin(e: any) -> None {
|
|
69
|
-
e.preventDefault();
|
|
70
|
-
setError("");
|
|
71
|
-
if not username or not password {
|
|
72
|
-
setError("Please fill in all fields");
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
success = await jacLogin(username, password);
|
|
76
|
-
if success {
|
|
77
|
-
navigate("/");
|
|
78
|
-
} else {
|
|
79
|
-
setError("Invalid credentials");
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
def handleUsernameChange(e: any) -> None {
|
|
84
|
-
setUsername(e.target.value);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
def handlePasswordChange(e: any) -> None {
|
|
88
|
-
setPassword(e.target.value);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
errorDisplay = None;
|
|
92
|
-
if error {
|
|
93
|
-
errorDisplay = <div
|
|
94
|
-
style={{"color": "#dc2626", "fontSize": "14px", "marginBottom": "12px"}}
|
|
95
|
-
>
|
|
96
|
-
{error}
|
|
97
|
-
</div>;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return <div
|
|
101
|
-
style={{
|
|
102
|
-
"minHeight": "calc(100vh - 56px)",
|
|
103
|
-
"display": "flex",
|
|
104
|
-
"alignItems": "center",
|
|
105
|
-
"justifyContent": "center",
|
|
106
|
-
"background": "#f5f5f5"
|
|
107
|
-
}}
|
|
108
|
-
>
|
|
109
|
-
<div
|
|
110
|
-
style={{
|
|
111
|
-
"background": "#ffffff",
|
|
112
|
-
"padding": "32px",
|
|
113
|
-
"borderRadius": "8px",
|
|
114
|
-
"width": "300px",
|
|
115
|
-
"boxShadow": "0 2px 8px rgba(0,0,0,0.1)"
|
|
116
|
-
}}
|
|
117
|
-
>
|
|
118
|
-
<h2
|
|
119
|
-
style={{"marginBottom": "24px", "textAlign": "center"}}
|
|
120
|
-
>
|
|
121
|
-
Login
|
|
122
|
-
</h2>
|
|
123
|
-
<form
|
|
124
|
-
onSubmit={handleLogin}
|
|
125
|
-
>
|
|
126
|
-
<input
|
|
127
|
-
type="text"
|
|
128
|
-
value={username}
|
|
129
|
-
onChange={handleUsernameChange}
|
|
130
|
-
placeholder="Username"
|
|
131
|
-
style={{
|
|
132
|
-
"width": "100%",
|
|
133
|
-
"padding": "10px",
|
|
134
|
-
"marginBottom": "12px",
|
|
135
|
-
"border": "1px solid #ddd",
|
|
136
|
-
"borderRadius": "4px",
|
|
137
|
-
"boxSizing": "border-box"
|
|
138
|
-
}}
|
|
139
|
-
/>
|
|
140
|
-
<input
|
|
141
|
-
type="password"
|
|
142
|
-
value={password}
|
|
143
|
-
onChange={handlePasswordChange}
|
|
144
|
-
placeholder="Password"
|
|
145
|
-
style={{
|
|
146
|
-
"width": "100%",
|
|
147
|
-
"padding": "10px",
|
|
148
|
-
"marginBottom": "12px",
|
|
149
|
-
"border": "1px solid #ddd",
|
|
150
|
-
"borderRadius": "4px",
|
|
151
|
-
"boxSizing": "border-box"
|
|
152
|
-
}}
|
|
153
|
-
/>
|
|
154
|
-
{errorDisplay}
|
|
155
|
-
<button
|
|
156
|
-
type="submit"
|
|
157
|
-
style={{
|
|
158
|
-
"width": "100%",
|
|
159
|
-
"padding": "10px",
|
|
160
|
-
"background": "#3b82f6",
|
|
161
|
-
"color": "#ffffff",
|
|
162
|
-
"border": "none",
|
|
163
|
-
"borderRadius": "4px",
|
|
164
|
-
"cursor": "pointer",
|
|
165
|
-
"fontWeight": "600"
|
|
166
|
-
}}
|
|
167
|
-
>
|
|
168
|
-
Login
|
|
169
|
-
</button>
|
|
170
|
-
</form>
|
|
171
|
-
<p
|
|
172
|
-
style={{
|
|
173
|
-
"textAlign": "center",
|
|
174
|
-
"marginTop": "16px",
|
|
175
|
-
"fontSize": "14px"
|
|
176
|
-
}}
|
|
177
|
-
>
|
|
178
|
-
Need an account?
|
|
179
|
-
{" "}
|
|
180
|
-
<Link to="/signup">
|
|
181
|
-
Sign up
|
|
182
|
-
</Link>
|
|
183
|
-
</p>
|
|
184
|
-
</div>
|
|
185
|
-
</div>;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
# Signup Page
|
|
189
|
-
def SignupPage -> any {
|
|
190
|
-
[username, setUsername] = useState("");
|
|
191
|
-
[password, setPassword] = useState("");
|
|
192
|
-
[error, setError] = useState("");
|
|
193
|
-
navigate = useNavigate();
|
|
194
|
-
|
|
195
|
-
async def handleSignup(e: any) -> None {
|
|
196
|
-
e.preventDefault();
|
|
197
|
-
setError("");
|
|
198
|
-
if not username or not password {
|
|
199
|
-
setError("Please fill in all fields");
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
result = await jacSignup(username, password);
|
|
203
|
-
if result["success"] {
|
|
204
|
-
navigate("/");
|
|
205
|
-
} else {
|
|
206
|
-
setError(result["error"] if result["error"] else "Signup failed");
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
def handleUsernameChange(e: any) -> None {
|
|
211
|
-
setUsername(e.target.value);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
def handlePasswordChange(e: any) -> None {
|
|
215
|
-
setPassword(e.target.value);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
errorDisplay = None;
|
|
219
|
-
if error {
|
|
220
|
-
errorDisplay = <div
|
|
221
|
-
style={{"color": "#dc2626", "fontSize": "14px", "marginBottom": "12px"}}
|
|
222
|
-
>
|
|
223
|
-
{error}
|
|
224
|
-
</div>;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return <div
|
|
228
|
-
style={{
|
|
229
|
-
"minHeight": "calc(100vh - 56px)",
|
|
230
|
-
"display": "flex",
|
|
231
|
-
"alignItems": "center",
|
|
232
|
-
"justifyContent": "center",
|
|
233
|
-
"background": "#f5f5f5"
|
|
234
|
-
}}
|
|
235
|
-
>
|
|
236
|
-
<div
|
|
237
|
-
style={{
|
|
238
|
-
"background": "#ffffff",
|
|
239
|
-
"padding": "32px",
|
|
240
|
-
"borderRadius": "8px",
|
|
241
|
-
"width": "300px",
|
|
242
|
-
"boxShadow": "0 2px 8px rgba(0,0,0,0.1)"
|
|
243
|
-
}}
|
|
244
|
-
>
|
|
245
|
-
<h2
|
|
246
|
-
style={{"marginBottom": "24px", "textAlign": "center"}}
|
|
247
|
-
>
|
|
248
|
-
Sign Up
|
|
249
|
-
</h2>
|
|
250
|
-
<form
|
|
251
|
-
onSubmit={handleSignup}
|
|
252
|
-
>
|
|
253
|
-
<input
|
|
254
|
-
type="text"
|
|
255
|
-
value={username}
|
|
256
|
-
onChange={handleUsernameChange}
|
|
257
|
-
placeholder="Username"
|
|
258
|
-
style={{
|
|
259
|
-
"width": "100%",
|
|
260
|
-
"padding": "10px",
|
|
261
|
-
"marginBottom": "12px",
|
|
262
|
-
"border": "1px solid #ddd",
|
|
263
|
-
"borderRadius": "4px",
|
|
264
|
-
"boxSizing": "border-box"
|
|
265
|
-
}}
|
|
266
|
-
/>
|
|
267
|
-
<input
|
|
268
|
-
type="password"
|
|
269
|
-
value={password}
|
|
270
|
-
onChange={handlePasswordChange}
|
|
271
|
-
placeholder="Password"
|
|
272
|
-
style={{
|
|
273
|
-
"width": "100%",
|
|
274
|
-
"padding": "10px",
|
|
275
|
-
"marginBottom": "12px",
|
|
276
|
-
"border": "1px solid #ddd",
|
|
277
|
-
"borderRadius": "4px",
|
|
278
|
-
"boxSizing": "border-box"
|
|
279
|
-
}}
|
|
280
|
-
/>
|
|
281
|
-
{errorDisplay}
|
|
282
|
-
<button
|
|
283
|
-
type="submit"
|
|
284
|
-
style={{
|
|
285
|
-
"width": "100%",
|
|
286
|
-
"padding": "10px",
|
|
287
|
-
"background": "#3b82f6",
|
|
288
|
-
"color": "#ffffff",
|
|
289
|
-
"border": "none",
|
|
290
|
-
"borderRadius": "4px",
|
|
291
|
-
"cursor": "pointer",
|
|
292
|
-
"fontWeight": "600"
|
|
293
|
-
}}
|
|
294
|
-
>
|
|
295
|
-
Sign Up
|
|
296
|
-
</button>
|
|
297
|
-
</form>
|
|
298
|
-
<p
|
|
299
|
-
style={{
|
|
300
|
-
"textAlign": "center",
|
|
301
|
-
"marginTop": "16px",
|
|
302
|
-
"fontSize": "14px"
|
|
303
|
-
}}
|
|
304
|
-
>
|
|
305
|
-
Have an account?
|
|
306
|
-
{" "}
|
|
307
|
-
<Link to="/login">
|
|
308
|
-
Login
|
|
309
|
-
</Link>
|
|
310
|
-
</p>
|
|
311
|
-
</div>
|
|
312
|
-
</div>;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
# Home page demonstrating CSS styling + direct asset usage + basic walkers
|
|
316
|
-
def Home -> any {
|
|
317
|
-
# Check if user is logged in, redirect if not
|
|
318
|
-
if not jacIsLoggedIn() {
|
|
319
|
-
return <Navigate to="/login" />;
|
|
320
|
-
}
|
|
321
|
-
[count, setCount] = useState(0);
|
|
322
|
-
[pingResult, setPingResult] = useState("");
|
|
323
|
-
[serverMessage, setServerMessage] = useState("");
|
|
324
|
-
[lastTodoMessage, setLastTodoMessage] = useState("");
|
|
325
|
-
|
|
326
|
-
useEffect(
|
|
327
|
-
lambda -> None{ console.log("Home count changed: ", count);} , [count]
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
# Call simple backend walkers
|
|
331
|
-
async def handlePing -> None {
|
|
332
|
-
result = root spawn ping_server();
|
|
333
|
-
if result.reports and result.reports.length > 0 {
|
|
334
|
-
setPingResult(result.reports[0][0]);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
async def loadServerMessage -> None {
|
|
339
|
-
result = root spawn get_server_message();
|
|
340
|
-
if result.reports and result.reports.length > 0 {
|
|
341
|
-
setServerMessage(result.reports[0][0]);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
# Create a sample Todo node in the graph with a hardcoded payload
|
|
346
|
-
async def handleCreateSampleTodo -> None {
|
|
347
|
-
result = root spawn create_todo(text="Sample todo from all-in-one app");
|
|
348
|
-
if result.reports and result.reports.length > 0 {
|
|
349
|
-
todo = result.reports[0][0];
|
|
350
|
-
setLastTodoMessage("Created Todo: " + todo.text);
|
|
351
|
-
console.log("Created Todo node:", todo);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
useEffect(lambda -> None{ loadServerMessage();} , []);
|
|
356
|
-
|
|
357
|
-
# Initialize a Web Worker and handle message-based communication
|
|
358
|
-
workerRef = useRef(null);
|
|
359
|
-
[message, setMessage] = useState("");
|
|
360
|
-
|
|
361
|
-
useEffect(lambda -> None {
|
|
362
|
-
workerRef.current = Reflect.construct(Worker, ["/workers/worker.js"]);
|
|
363
|
-
workerRef.current.onmessage = lambda event: any -> None {
|
|
364
|
-
console.log("Message received from worker:", event.data);
|
|
365
|
-
setMessage(event.data);
|
|
366
|
-
};
|
|
367
|
-
return (lambda -> None {
|
|
368
|
-
workerRef.current.terminate();
|
|
369
|
-
});
|
|
370
|
-
}, []);
|
|
371
|
-
handleClick = lambda -> None {
|
|
372
|
-
workerRef.current.postMessage("");
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
return <div
|
|
376
|
-
style={{
|
|
377
|
-
"padding": "2rem",
|
|
378
|
-
"fontFamily": "system-ui, -apple-system, sans-serif"
|
|
379
|
-
}}
|
|
380
|
-
>
|
|
381
|
-
<h1>
|
|
382
|
-
🍔 Router + Styling + Assets Demo
|
|
383
|
-
</h1>
|
|
384
|
-
<p>
|
|
385
|
-
This home page combines
|
|
386
|
-
{" "}
|
|
387
|
-
<strong>
|
|
388
|
-
React Router,
|
|
389
|
-
</strong>
|
|
390
|
-
{" "}
|
|
391
|
-
<strong>
|
|
392
|
-
pure CSS styling,
|
|
393
|
-
</strong>
|
|
394
|
-
{" "}
|
|
395
|
-
<strong>
|
|
396
|
-
static assets
|
|
397
|
-
</strong>
|
|
398
|
-
{" "}
|
|
399
|
-
and
|
|
400
|
-
{" "}
|
|
401
|
-
<strong>
|
|
402
|
-
nested folder imports
|
|
403
|
-
</strong>
|
|
404
|
-
</p>
|
|
405
|
-
<div className="container">
|
|
406
|
-
<h2
|
|
407
|
-
style={{
|
|
408
|
-
"color": "white",
|
|
409
|
-
"textShadow": "2px 2px 4px rgba(0,0,0,0.6)"
|
|
410
|
-
}}
|
|
411
|
-
>
|
|
412
|
-
CSS Background Image
|
|
413
|
-
</h2>
|
|
414
|
-
<p
|
|
415
|
-
style={{
|
|
416
|
-
"color": "white",
|
|
417
|
-
"maxWidth": "480px",
|
|
418
|
-
"textShadow": "1px 1px 3px rgba(0,0,0,0.7)"
|
|
419
|
-
}}
|
|
420
|
-
>
|
|
421
|
-
This section uses the burger image as a background via CSS, just like the
|
|
422
|
-
{" "}
|
|
423
|
-
<code>
|
|
424
|
-
asset-serving/css-with-image
|
|
425
|
-
</code>
|
|
426
|
-
{" "}
|
|
427
|
-
example.
|
|
428
|
-
</p>
|
|
429
|
-
</div>
|
|
430
|
-
<Card
|
|
431
|
-
title="TypeScript Card Component"
|
|
432
|
-
description="This card is built with TypeScript and demonstrates type-safe component usage in Jac"
|
|
433
|
-
variant="highlighted"
|
|
434
|
-
>
|
|
435
|
-
<p
|
|
436
|
-
style={{"margin": "0.5rem 0", "color": "#374151"}}
|
|
437
|
-
>
|
|
438
|
-
This is a TypeScript component imported and used in Jac code!
|
|
439
|
-
</p>
|
|
440
|
-
</Card>
|
|
441
|
-
<div className="card">
|
|
442
|
-
<h3>
|
|
443
|
-
Direct <img> asset
|
|
444
|
-
</h3>
|
|
445
|
-
<img
|
|
446
|
-
src="/static/assets/burger.png"
|
|
447
|
-
alt="Burger asset served by Jac"
|
|
448
|
-
className="burgerImage"
|
|
449
|
-
/>
|
|
450
|
-
<p
|
|
451
|
-
style={{"marginTop": "0.75rem", "color": "#555"}}
|
|
452
|
-
>
|
|
453
|
-
This image is served from the project
|
|
454
|
-
{" "}
|
|
455
|
-
<code>
|
|
456
|
-
assets/
|
|
457
|
-
</code>
|
|
458
|
-
{" "}
|
|
459
|
-
folder using the
|
|
460
|
-
{" "}
|
|
461
|
-
<code>
|
|
462
|
-
/static/assets/
|
|
463
|
-
</code>
|
|
464
|
-
{" "}
|
|
465
|
-
path.
|
|
466
|
-
</p>
|
|
467
|
-
</div>
|
|
468
|
-
<div
|
|
469
|
-
style={{"marginTop": "2rem"}}
|
|
470
|
-
>
|
|
471
|
-
<h3>
|
|
472
|
-
Counter with pure CSS classes
|
|
473
|
-
</h3>
|
|
474
|
-
<p>
|
|
475
|
-
You've clicked the burger
|
|
476
|
-
{" "}
|
|
477
|
-
<strong>
|
|
478
|
-
{count}
|
|
479
|
-
</strong>
|
|
480
|
-
{" "}
|
|
481
|
-
times.
|
|
482
|
-
</p>
|
|
483
|
-
<button
|
|
484
|
-
onClick={lambda e: any -> None{ setCount(count + 1);} }
|
|
485
|
-
style={{
|
|
486
|
-
"padding": "0.6rem 1.4rem",
|
|
487
|
-
"fontSize": "1rem",
|
|
488
|
-
"backgroundColor": "#ff6b35",
|
|
489
|
-
"color": "white",
|
|
490
|
-
"border": "none",
|
|
491
|
-
"borderRadius": "6px",
|
|
492
|
-
"cursor": "pointer",
|
|
493
|
-
"boxShadow": "0 2px 4px rgba(0,0,0,0.2)"
|
|
494
|
-
}}
|
|
495
|
-
>
|
|
496
|
-
Click the Burger! 🍔
|
|
497
|
-
</button>
|
|
498
|
-
</div>
|
|
499
|
-
<div
|
|
500
|
-
style={{"marginTop": "2rem"}}
|
|
501
|
-
>
|
|
502
|
-
<h3>
|
|
503
|
-
Backend Walkers
|
|
504
|
-
</h3>
|
|
505
|
-
<p>
|
|
506
|
-
Basic example walkers:
|
|
507
|
-
{" "}
|
|
508
|
-
<code>
|
|
509
|
-
ping_server
|
|
510
|
-
</code>
|
|
511
|
-
{" "}
|
|
512
|
-
and
|
|
513
|
-
{" "}
|
|
514
|
-
<code>
|
|
515
|
-
get_server_message
|
|
516
|
-
</code>
|
|
517
|
-
</p>
|
|
518
|
-
<button
|
|
519
|
-
onClick={lambda e: any -> None{ handlePing();} }
|
|
520
|
-
style={{
|
|
521
|
-
"padding": "0.5rem 1.2rem",
|
|
522
|
-
"marginRight": "0.75rem",
|
|
523
|
-
"backgroundColor": "#3b82f6",
|
|
524
|
-
"color": "white",
|
|
525
|
-
"border": "none",
|
|
526
|
-
"borderRadius": "6px",
|
|
527
|
-
"cursor": "pointer"
|
|
528
|
-
}}
|
|
529
|
-
>
|
|
530
|
-
Ping Backend
|
|
531
|
-
</button>
|
|
532
|
-
<button
|
|
533
|
-
onClick={lambda e: any -> None{ handleCreateSampleTodo();} }
|
|
534
|
-
style={{
|
|
535
|
-
"padding": "0.5rem 1.2rem",
|
|
536
|
-
"backgroundColor": "#10b981",
|
|
537
|
-
"color": "white",
|
|
538
|
-
"border": "none",
|
|
539
|
-
"borderRadius": "6px",
|
|
540
|
-
"cursor": "pointer"
|
|
541
|
-
}}
|
|
542
|
-
>
|
|
543
|
-
Create Sample Todo
|
|
544
|
-
</button>
|
|
545
|
-
{pingResult
|
|
546
|
-
and (
|
|
547
|
-
<span
|
|
548
|
-
style={{"marginLeft": "0.5rem", "color": "#374151"}}
|
|
549
|
-
>
|
|
550
|
-
Result:
|
|
551
|
-
{" "}
|
|
552
|
-
<code>
|
|
553
|
-
{pingResult}
|
|
554
|
-
</code>
|
|
555
|
-
</span>
|
|
556
|
-
)}
|
|
557
|
-
{serverMessage
|
|
558
|
-
and (
|
|
559
|
-
<p
|
|
560
|
-
style={{"marginTop": "0.75rem", "color": "#374151"}}
|
|
561
|
-
>
|
|
562
|
-
Message:
|
|
563
|
-
{" "}
|
|
564
|
-
<code>
|
|
565
|
-
{serverMessage}
|
|
566
|
-
</code>
|
|
567
|
-
</p>
|
|
568
|
-
)}
|
|
569
|
-
{lastTodoMessage
|
|
570
|
-
and (
|
|
571
|
-
<p
|
|
572
|
-
style={{"marginTop": "0.5rem", "color": "#111827"}}
|
|
573
|
-
>
|
|
574
|
-
{lastTodoMessage}
|
|
575
|
-
</p>
|
|
576
|
-
)}
|
|
577
|
-
</div>
|
|
578
|
-
<div
|
|
579
|
-
style={{"marginTop": "2rem"}}
|
|
580
|
-
>
|
|
581
|
-
<h3>
|
|
582
|
-
Web Worker
|
|
583
|
-
</h3>
|
|
584
|
-
<p>
|
|
585
|
-
This demonstrates how to communicate with a
|
|
586
|
-
{" "}
|
|
587
|
-
<strong>Python backend worker</strong>
|
|
588
|
-
{" "}
|
|
589
|
-
using Web Workers for asynchronous processing.
|
|
590
|
-
</p>
|
|
591
|
-
<p
|
|
592
|
-
style={{"fontSize": "0.9rem", "color": "#666", "marginTop": "0.5rem"}}
|
|
593
|
-
>
|
|
594
|
-
File:
|
|
595
|
-
{" "}
|
|
596
|
-
<code>
|
|
597
|
-
worker.py
|
|
598
|
-
</code>
|
|
599
|
-
{" "}
|
|
600
|
-
— Runs in a separate thread to avoid blocking the UI.
|
|
601
|
-
</p>
|
|
602
|
-
<button
|
|
603
|
-
onClick={lambda -> None { handleClick(); }}
|
|
604
|
-
style={{
|
|
605
|
-
"padding": "0.5rem 1.2rem",
|
|
606
|
-
"marginRight": "0.75rem",
|
|
607
|
-
"backgroundColor": "#d73bf6ff",
|
|
608
|
-
"color": "white",
|
|
609
|
-
"border": "none",
|
|
610
|
-
"borderRadius": "6px",
|
|
611
|
-
"cursor": "pointer"
|
|
612
|
-
}}
|
|
613
|
-
>
|
|
614
|
-
Call Python Worker
|
|
615
|
-
</button>
|
|
616
|
-
{message && (
|
|
617
|
-
<p style={{ marginTop: "1rem", fontWeight: "bold" }}>
|
|
618
|
-
{message}
|
|
619
|
-
</p>
|
|
620
|
-
)}
|
|
621
|
-
</div>
|
|
622
|
-
</div>;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
# Page showing nested imports from different folders
|
|
626
|
-
def NestedImportsDemo -> any {
|
|
627
|
-
# Check if user is logged in, redirect if not
|
|
628
|
-
if not jacIsLoggedIn() {
|
|
629
|
-
return <Navigate to="/login" />;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
return <div
|
|
633
|
-
style={{
|
|
634
|
-
"padding": "2rem",
|
|
635
|
-
"fontFamily": "system-ui, -apple-system, sans-serif"
|
|
636
|
-
}}
|
|
637
|
-
>
|
|
638
|
-
<h1>
|
|
639
|
-
📁 Nested Folder Imports
|
|
640
|
-
</h1>
|
|
641
|
-
<p>
|
|
642
|
-
This page mirrors the
|
|
643
|
-
{" "}
|
|
644
|
-
<code>
|
|
645
|
-
nested-folders/nested-basic
|
|
646
|
-
</code>
|
|
647
|
-
{" "}
|
|
648
|
-
example by importing components from both
|
|
649
|
-
{" "}
|
|
650
|
-
<code>
|
|
651
|
-
components.button
|
|
652
|
-
</code>
|
|
653
|
-
{" "}
|
|
654
|
-
and
|
|
655
|
-
{" "}
|
|
656
|
-
<code>
|
|
657
|
-
button
|
|
658
|
-
</code>
|
|
659
|
-
</p>
|
|
660
|
-
<p
|
|
661
|
-
style={{"marginTop": "0.75rem"}}
|
|
662
|
-
>
|
|
663
|
-
Both buttons below are rendered via relative imports:
|
|
664
|
-
</p>
|
|
665
|
-
<div
|
|
666
|
-
style={{"display": "flex", "gap": "1rem", "marginTop": "1.5rem"}}
|
|
667
|
-
>
|
|
668
|
-
<CustomButton />
|
|
669
|
-
<CustomButtonRoot />
|
|
670
|
-
</div>
|
|
671
|
-
</div>;
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
# Simple 404 page
|
|
675
|
-
def NotFound -> any {
|
|
676
|
-
return <div
|
|
677
|
-
style={{
|
|
678
|
-
"padding": "2rem",
|
|
679
|
-
"textAlign": "center",
|
|
680
|
-
"fontFamily": "system-ui, -apple-system, sans-serif"
|
|
681
|
-
}}
|
|
682
|
-
>
|
|
683
|
-
<h1>
|
|
684
|
-
🔍 404 - Page Not Found
|
|
685
|
-
</h1>
|
|
686
|
-
<p>
|
|
687
|
-
The page you are looking for does not exist.
|
|
688
|
-
</p>
|
|
689
|
-
<Link to="/">
|
|
690
|
-
← Back to Home
|
|
691
|
-
</Link>
|
|
692
|
-
</div>;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
# Navigation component with active link styling and auth
|
|
696
|
-
def Navigation -> any {
|
|
697
|
-
location = useLocation();
|
|
698
|
-
isLoggedIn = jacIsLoggedIn();
|
|
699
|
-
navigate = useNavigate();
|
|
700
|
-
|
|
701
|
-
def linkStyle(path: str) -> dict {
|
|
702
|
-
isActive = location.pathname == path;
|
|
703
|
-
return {
|
|
704
|
-
"padding": "0.5rem 1rem",
|
|
705
|
-
"textDecoration": "none",
|
|
706
|
-
"color": "#0066cc" if isActive else "#333",
|
|
707
|
-
"fontWeight": "bold" if isActive else "normal",
|
|
708
|
-
"backgroundColor": "#e3f2fd" if isActive else "transparent",
|
|
709
|
-
"borderRadius": "4px",
|
|
710
|
-
"display": "inline-block"
|
|
711
|
-
};
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
def handleLogout(e: any) -> None {
|
|
715
|
-
e.preventDefault();
|
|
716
|
-
jacLogout();
|
|
717
|
-
navigate("/login");
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
authButtons = None;
|
|
721
|
-
if isLoggedIn {
|
|
722
|
-
authButtons = <button
|
|
723
|
-
onClick={handleLogout}
|
|
724
|
-
style={{
|
|
725
|
-
"padding": "0.5rem 1rem",
|
|
726
|
-
"background": "#ef4444",
|
|
727
|
-
"color": "#ffffff",
|
|
728
|
-
"border": "none",
|
|
729
|
-
"borderRadius": "4px",
|
|
730
|
-
"cursor": "pointer",
|
|
731
|
-
"fontWeight": "600"
|
|
732
|
-
}}
|
|
733
|
-
>
|
|
734
|
-
Logout
|
|
735
|
-
</button>;
|
|
736
|
-
} else {
|
|
737
|
-
authButtons = <>
|
|
738
|
-
<Link
|
|
739
|
-
to="/login"
|
|
740
|
-
style={linkStyle("/login")}
|
|
741
|
-
>
|
|
742
|
-
Login
|
|
743
|
-
</Link>
|
|
744
|
-
<Link
|
|
745
|
-
to="/signup"
|
|
746
|
-
style={linkStyle("/signup")}
|
|
747
|
-
>
|
|
748
|
-
Sign Up
|
|
749
|
-
</Link>
|
|
750
|
-
</>;
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
return <nav
|
|
754
|
-
style={{
|
|
755
|
-
"padding": "1rem",
|
|
756
|
-
"backgroundColor": "#f5f5f5",
|
|
757
|
-
"marginBottom": "2rem",
|
|
758
|
-
"boxShadow": "0 2px 4px rgba(0,0,0,0.1)"
|
|
759
|
-
}}
|
|
760
|
-
>
|
|
761
|
-
<div
|
|
762
|
-
style={{
|
|
763
|
-
"maxWidth": "1200px",
|
|
764
|
-
"margin": "0 auto",
|
|
765
|
-
"display": "flex",
|
|
766
|
-
"gap": "1rem",
|
|
767
|
-
"alignItems": "center",
|
|
768
|
-
"justifyContent": "space-between"
|
|
769
|
-
}}
|
|
770
|
-
>
|
|
771
|
-
<div
|
|
772
|
-
style={{"display": "flex", "gap": "1rem", "alignItems": "center"}}
|
|
773
|
-
>
|
|
774
|
-
{isLoggedIn
|
|
775
|
-
and (
|
|
776
|
-
<>
|
|
777
|
-
<Link
|
|
778
|
-
to="/"
|
|
779
|
-
style={linkStyle("/")}
|
|
780
|
-
>
|
|
781
|
-
Home
|
|
782
|
-
</Link>
|
|
783
|
-
<Link
|
|
784
|
-
to="/nested"
|
|
785
|
-
style={linkStyle("/nested")}
|
|
786
|
-
>
|
|
787
|
-
Nested Imports
|
|
788
|
-
</Link>
|
|
789
|
-
</>
|
|
790
|
-
)}
|
|
791
|
-
</div>
|
|
792
|
-
<div
|
|
793
|
-
style={{"display": "flex", "gap": "1rem", "alignItems": "center"}}
|
|
794
|
-
>
|
|
795
|
-
{authButtons}
|
|
796
|
-
</div>
|
|
797
|
-
</div>
|
|
798
|
-
</nav>;
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
# Main app wrapped in Router (same API as with-router/ example)
|
|
802
|
-
def:pub app -> any {
|
|
803
|
-
return <Router>
|
|
804
|
-
<div
|
|
805
|
-
style={{"fontFamily": "system-ui, -apple-system, sans-serif"}}
|
|
806
|
-
>
|
|
807
|
-
<Navigation />
|
|
808
|
-
<div
|
|
809
|
-
style={{
|
|
810
|
-
"maxWidth": "960px",
|
|
811
|
-
"margin": "0 auto",
|
|
812
|
-
"padding": "0 1rem 3rem 1rem"
|
|
813
|
-
}}
|
|
814
|
-
>
|
|
815
|
-
<Routes>
|
|
816
|
-
<Route
|
|
817
|
-
path="/"
|
|
818
|
-
element={<Home />}
|
|
819
|
-
/>
|
|
820
|
-
<Route
|
|
821
|
-
path="/login"
|
|
822
|
-
element={<LoginPage />}
|
|
823
|
-
/>
|
|
824
|
-
<Route
|
|
825
|
-
path="/signup"
|
|
826
|
-
element={<SignupPage />}
|
|
827
|
-
/>
|
|
828
|
-
<Route
|
|
829
|
-
path="/nested"
|
|
830
|
-
element={<NestedImportsDemo />}
|
|
831
|
-
/>
|
|
832
|
-
<Route
|
|
833
|
-
path="*"
|
|
834
|
-
element={<NotFound />}
|
|
835
|
-
/>
|
|
836
|
-
</Routes>
|
|
837
|
-
</div>
|
|
838
|
-
</div>
|
|
839
|
-
</Router>;
|
|
840
|
-
}
|
|
841
|
-
}
|