jac-client 0.2.8__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/button.jac +4 -3
- jac_client/examples/all-in-one/components/CategoryFilter.jac +36 -24
- jac_client/examples/all-in-one/components/Header.jac +12 -8
- jac_client/examples/all-in-one/components/ProfitOverview.jac +49 -35
- jac_client/examples/all-in-one/components/Summary.jac +59 -36
- jac_client/examples/all-in-one/components/TransactionForm.jac +142 -112
- jac_client/examples/all-in-one/components/TransactionItem.jac +37 -30
- jac_client/examples/all-in-one/components/TransactionList.jac +33 -26
- jac_client/examples/all-in-one/components/button.jac +4 -3
- jac_client/examples/all-in-one/components/navigation.jac +111 -117
- jac_client/examples/all-in-one/constants/categories.jac +23 -24
- jac_client/examples/all-in-one/constants/clients.jac +7 -8
- jac_client/examples/all-in-one/context/BudgetContext.jac +9 -6
- jac_client/examples/all-in-one/hooks/useBudget.jac +18 -12
- jac_client/examples/all-in-one/hooks/useLocalStorage.jac +14 -13
- jac_client/examples/all-in-one/main.jac +542 -0
- jac_client/examples/all-in-one/pages/BudgetPlanner.jac +26 -12
- jac_client/examples/all-in-one/pages/FeaturesTest.jac +43 -12
- jac_client/examples/all-in-one/pages/LandingPage.jac +113 -90
- 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 +114 -119
- jac_client/examples/all-in-one/pages/nestedDemo.jac +44 -51
- jac_client/examples/all-in-one/pages/notFound.jac +15 -21
- jac_client/examples/all-in-one/pages/signupPage.jac +113 -119
- jac_client/examples/all-in-one/utils/formatters.jac +5 -8
- 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 +491 -411
- jac_client/plugin/client.jac +25 -0
- jac_client/plugin/client_runtime.cl.jac +10 -4
- jac_client/plugin/impl/client.impl.jac +96 -55
- jac_client/plugin/impl/client_runtime.impl.jac +155 -1
- jac_client/plugin/plugin_config.jac +211 -29
- jac_client/plugin/src/__init__.jac +0 -2
- jac_client/plugin/src/compiler.jac +0 -1
- 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 +49 -17
- 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 +191 -64
- 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 +6 -0
- 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 +103 -47
- jac_client/tests/fixtures/spawn_test/app.jac +49 -52
- jac_client/tests/fixtures/with-ts/app.jac +27 -27
- jac_client/tests/test_cli.py +182 -71
- jac_client/tests/test_e2e.py +232 -0
- jac_client/tests/test_helpers.py +58 -0
- jac_client/tests/test_it.py +91 -135
- jac_client/tests/test_it_desktop.py +891 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/METADATA +6 -6
- jac_client-0.2.11.dist-info/RECORD +113 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/WHEEL +1 -1
- jac_client/examples/all-in-one/app.jac +0 -573
- jac_client/examples/all-in-one/pages/BudgetPlanner.cl.jac +0 -70
- jac_client/examples/all-in-one/pages/FeaturesTest.cl.jac +0 -552
- 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 -371
- jac_client/examples/basic-auth-with-router/src/app.jac +0 -464
- jac_client/examples/basic-full-stack/src/app.jac +0 -359
- 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 -89
- jac_client-0.2.8.dist-info/RECORD +0 -97
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/entry_points.txt +0 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
import from datetime { datetime, timedelta }
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Basic backend walkers
|
|
5
|
+
#
|
|
6
|
+
node Todo {
|
|
7
|
+
has text: str,
|
|
8
|
+
done: bool = False;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
walker:pub create_todo {
|
|
12
|
+
has text: str;
|
|
13
|
+
|
|
14
|
+
can create with `root entry {
|
|
15
|
+
new_todo = here ++> Todo(text=self.text);
|
|
16
|
+
report new_todo;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
walker:pub ping_server {
|
|
21
|
+
can ping with `root entry {
|
|
22
|
+
report "pong from backend!";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
walker:pub get_server_message {
|
|
27
|
+
can info with `root entry {
|
|
28
|
+
report "hello from a basic walker!";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Features Test Page - Backend Logic
|
|
33
|
+
# This file is intentionally kept empty to demonstrate the separation of concerns
|
|
34
|
+
# where UI logic resides in .cl.jac files and backend walker logic in app.jac
|
|
35
|
+
|
|
36
|
+
# All walker implementations for this feature are in main.jac
|
|
37
|
+
# This demonstrates that you can have separate .jac files for different purposes
|
|
38
|
+
# Features Test - Backend Walkers
|
|
39
|
+
# This file demonstrates walker functionality for testing various JAC features
|
|
40
|
+
|
|
41
|
+
# Node definition for storing test data
|
|
42
|
+
node TestData {
|
|
43
|
+
has message: str,
|
|
44
|
+
count: int = 0,
|
|
45
|
+
created_at: str = "";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Walker: Create test data
|
|
49
|
+
walker create_test_data {
|
|
50
|
+
has message: str;
|
|
51
|
+
|
|
52
|
+
can create with `root entry {
|
|
53
|
+
new_data = here ++> TestData(
|
|
54
|
+
message=self.message,
|
|
55
|
+
count=1,
|
|
56
|
+
created_at=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
57
|
+
);
|
|
58
|
+
report new_data;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Walker: Read all test data
|
|
63
|
+
walker read_test_data {
|
|
64
|
+
can read with `root entry {
|
|
65
|
+
visit [-->(`?TestData)];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
can report_data with exit {
|
|
69
|
+
report here;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Walker: Update test data
|
|
74
|
+
walker update_test_data {
|
|
75
|
+
has new_message: str;
|
|
76
|
+
|
|
77
|
+
can update with TestData entry {
|
|
78
|
+
here.message = self.new_message;
|
|
79
|
+
here.count = here.count + 1;
|
|
80
|
+
report here;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Walker: Delete test data
|
|
85
|
+
walker delete_test_data {
|
|
86
|
+
can delete with TestData entry {
|
|
87
|
+
del here;
|
|
88
|
+
report {"status": "deleted"};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Walker: String manipulation test
|
|
93
|
+
walker test_string_methods {
|
|
94
|
+
has input_text: str;
|
|
95
|
+
|
|
96
|
+
can process with `root entry {
|
|
97
|
+
result = {
|
|
98
|
+
"original": self.input_text,
|
|
99
|
+
"uppercase": self.input_text.upper(),
|
|
100
|
+
"lowercase": self.input_text.lower(),
|
|
101
|
+
"capitalized": self.input_text.capitalize(),
|
|
102
|
+
"reversed": self.input_text[::-1],
|
|
103
|
+
"length": len(self.input_text),
|
|
104
|
+
"words": self.input_text.split(),
|
|
105
|
+
"trimmed": self.input_text.strip(),
|
|
106
|
+
"replaced": self.input_text.replace("test", "demo")
|
|
107
|
+
};
|
|
108
|
+
report result;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# Walker: Array/List operations test
|
|
113
|
+
walker test_list_operations {
|
|
114
|
+
has numbers: list;
|
|
115
|
+
|
|
116
|
+
can process with `root entry {
|
|
117
|
+
result = {
|
|
118
|
+
"original": self.numbers,
|
|
119
|
+
"sorted": sorted(self.numbers),
|
|
120
|
+
"reversed": list(reversed(self.numbers)),
|
|
121
|
+
"sum": sum(self.numbers),
|
|
122
|
+
"max": max(self.numbers) if len(self.numbers) > 0 else 0,
|
|
123
|
+
"min": min(self.numbers) if len(self.numbers) > 0 else 0,
|
|
124
|
+
"length": len(self.numbers),
|
|
125
|
+
"doubled": [x * 2 for x in self.numbers]
|
|
126
|
+
};
|
|
127
|
+
report result;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# Walker: Complex data processing
|
|
132
|
+
walker process_complex_data {
|
|
133
|
+
has items: list;
|
|
134
|
+
|
|
135
|
+
can process with `root entry {
|
|
136
|
+
processed = [];
|
|
137
|
+
for item in self.items {
|
|
138
|
+
processed.append(
|
|
139
|
+
{
|
|
140
|
+
"id": item.get("id", 0),
|
|
141
|
+
"name": item.get("name", "").upper(),
|
|
142
|
+
"value": item.get("value", 0) * 2,
|
|
143
|
+
"processed_at": datetime.now().strftime("%H:%M:%S")
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
result = {
|
|
149
|
+
"original_count": len(self.items),
|
|
150
|
+
"processed_count": len(processed),
|
|
151
|
+
"items": processed,
|
|
152
|
+
"total_value": sum([p["value"] for p in processed])
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
report result;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
#
|
|
160
|
+
# Combined example: auth + routing + CSS styling + asset serving + nested folder imports
|
|
161
|
+
#
|
|
162
|
+
cl import from react { useEffect, useRef }
|
|
163
|
+
cl import from "@jac/runtime" {
|
|
164
|
+
Router,
|
|
165
|
+
Routes,
|
|
166
|
+
Route,
|
|
167
|
+
Link,
|
|
168
|
+
useNavigate,
|
|
169
|
+
Navigate,
|
|
170
|
+
jacIsLoggedIn
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# Pure CSS + asset-in-CSS example
|
|
174
|
+
cl import ".styles/styles.css";
|
|
175
|
+
|
|
176
|
+
# Login Page
|
|
177
|
+
cl import from .pages.loginPage { LoginPage }
|
|
178
|
+
|
|
179
|
+
# Signup Page
|
|
180
|
+
cl import from .pages.signupPage { SignupPage }
|
|
181
|
+
|
|
182
|
+
# Simple 404 page
|
|
183
|
+
cl import from .pages.notFound { NotFound }
|
|
184
|
+
|
|
185
|
+
# Navigation component with active link styling and auth
|
|
186
|
+
cl import from .components.navigation {
|
|
187
|
+
Navigation
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# Page showing nested imports from different folders
|
|
191
|
+
cl import from .pages.nestedDemo {
|
|
192
|
+
NestedImportsDemo
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
cl import from .pages.FeaturesTest { FeaturesTest }
|
|
196
|
+
|
|
197
|
+
cl import from .pages.LandingPage { LandingPage }
|
|
198
|
+
|
|
199
|
+
cl import from .pages.BudgetPlanner { BudgetPlanner }
|
|
200
|
+
|
|
201
|
+
# Context provider
|
|
202
|
+
cl import from .context.BudgetContext { BudgetProvider }
|
|
203
|
+
|
|
204
|
+
# TypeScript component import
|
|
205
|
+
cl import from ".components/Card.tsx" { Card }
|
|
206
|
+
|
|
207
|
+
# Main app wrapped in Router (same API as with-router/ example)
|
|
208
|
+
cl {
|
|
209
|
+
def:pub HomePage -> any {
|
|
210
|
+
# Check if user is logged in, redirect if not
|
|
211
|
+
if not jacIsLoggedIn() {
|
|
212
|
+
return
|
|
213
|
+
<Navigate to="/login" />;
|
|
214
|
+
}
|
|
215
|
+
has count: int = 0,
|
|
216
|
+
pingResult: str = "",
|
|
217
|
+
serverMessage: str = "",
|
|
218
|
+
lastTodoMessage: str = "";
|
|
219
|
+
|
|
220
|
+
can with count entry {
|
|
221
|
+
console.log("Home count changed: ", count);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
# Call simple backend walkers
|
|
225
|
+
async def handlePing -> None {
|
|
226
|
+
result = root spawn ping_server();
|
|
227
|
+
if result.reports and result.reports.length > 0 {
|
|
228
|
+
pingResult = result.reports[0][0];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async def loadServerMessage -> None {
|
|
233
|
+
result = root spawn get_server_message();
|
|
234
|
+
if result.reports and result.reports.length > 0 {
|
|
235
|
+
serverMessage = result.reports[0][0];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# Create a sample Todo node in the graph with a hardcoded payload
|
|
240
|
+
async def handleCreateSampleTodo -> None {
|
|
241
|
+
result = root spawn create_todo(text="Sample todo from all-in-one app");
|
|
242
|
+
if result.reports and result.reports.length > 0 {
|
|
243
|
+
todo = result.reports[0][0];
|
|
244
|
+
lastTodoMessage = "Created Todo: " + todo.text;
|
|
245
|
+
console.log("Created Todo node:", todo);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async can with entry {
|
|
250
|
+
await loadServerMessage();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
# Initialize a Web Worker and handle message-based communication
|
|
254
|
+
workerRef = useRef(None);
|
|
255
|
+
has message: str = "";
|
|
256
|
+
|
|
257
|
+
useEffect(
|
|
258
|
+
lambda -> None { workerRef.current = Reflect.construct(
|
|
259
|
+
Worker, ["/workers/worker.js"]
|
|
260
|
+
);workerRef.current.onmessage = lambda event: any -> None { console.log(
|
|
261
|
+
"Message received from worker:", event.data
|
|
262
|
+
);message = event.data;};return (
|
|
263
|
+
lambda -> None { workerRef.current.terminate();}
|
|
264
|
+
); },
|
|
265
|
+
[]
|
|
266
|
+
);
|
|
267
|
+
handleClick = lambda -> None { workerRef.current.postMessage("");};
|
|
268
|
+
|
|
269
|
+
return
|
|
270
|
+
<div
|
|
271
|
+
style={{
|
|
272
|
+
"padding": "2rem",
|
|
273
|
+
"fontFamily": "system-ui, -apple-system, sans-serif"
|
|
274
|
+
}}
|
|
275
|
+
>
|
|
276
|
+
<h1>
|
|
277
|
+
🍔 Router + Styling + Assets Demo
|
|
278
|
+
</h1>
|
|
279
|
+
<p>
|
|
280
|
+
This home page combines
|
|
281
|
+
{" "}
|
|
282
|
+
<strong>
|
|
283
|
+
React Router,
|
|
284
|
+
</strong>
|
|
285
|
+
{" "}
|
|
286
|
+
<strong>
|
|
287
|
+
pure CSS styling,
|
|
288
|
+
</strong>
|
|
289
|
+
{" "}
|
|
290
|
+
<strong>
|
|
291
|
+
staticassets
|
|
292
|
+
</strong>
|
|
293
|
+
{" "}
|
|
294
|
+
and
|
|
295
|
+
{" "}
|
|
296
|
+
<strong>
|
|
297
|
+
nested folder imports
|
|
298
|
+
</strong>
|
|
299
|
+
</p>
|
|
300
|
+
<div className="container">
|
|
301
|
+
<h2
|
|
302
|
+
style={{
|
|
303
|
+
"color": "white",
|
|
304
|
+
"textShadow": "2px 2px 4px rgba(0,0,0,0.6)"
|
|
305
|
+
}}
|
|
306
|
+
>
|
|
307
|
+
CSS Background Image
|
|
308
|
+
</h2>
|
|
309
|
+
<p
|
|
310
|
+
style={{
|
|
311
|
+
"color": "white",
|
|
312
|
+
"maxWidth": "480px",
|
|
313
|
+
"textShadow": "1px 1px 3px rgba(0,0,0,0.7)"
|
|
314
|
+
}}
|
|
315
|
+
>
|
|
316
|
+
This section uses the burger image as a background via CSS, just like the
|
|
317
|
+
{" "}
|
|
318
|
+
<code>
|
|
319
|
+
asset-serving/css-with-image
|
|
320
|
+
</code>
|
|
321
|
+
{" "}
|
|
322
|
+
example.
|
|
323
|
+
</p>
|
|
324
|
+
</div>
|
|
325
|
+
<Card
|
|
326
|
+
title="TypeScript Card Component"
|
|
327
|
+
description="This card is built with TypeScript and demonstrates type-safe component usage in Jac"
|
|
328
|
+
variant="highlighted"
|
|
329
|
+
>
|
|
330
|
+
<p style={{"margin": "0.5rem 0", "color": "#374151"}}>
|
|
331
|
+
This is a TypeScript component imported and used in Jac code!
|
|
332
|
+
</p>
|
|
333
|
+
</Card>
|
|
334
|
+
<div className="card">
|
|
335
|
+
<h3>
|
|
336
|
+
Direct <img> asset
|
|
337
|
+
</h3>
|
|
338
|
+
<img
|
|
339
|
+
src="/static/assets/burger.png"
|
|
340
|
+
alt="Burger asset served by Jac"
|
|
341
|
+
className="burgerImage"
|
|
342
|
+
/>
|
|
343
|
+
<p style={{"marginTop": "0.75rem", "color": "#555"}}>
|
|
344
|
+
This image is served from the project
|
|
345
|
+
{" "}
|
|
346
|
+
<code>
|
|
347
|
+
assets/
|
|
348
|
+
</code>
|
|
349
|
+
{" "}
|
|
350
|
+
folder using the
|
|
351
|
+
{" "}
|
|
352
|
+
<code>
|
|
353
|
+
/static/assets/
|
|
354
|
+
</code>
|
|
355
|
+
{" "}
|
|
356
|
+
path.
|
|
357
|
+
</p>
|
|
358
|
+
</div>
|
|
359
|
+
<div style={{"marginTop": "2rem"}}>
|
|
360
|
+
<h3>
|
|
361
|
+
Counter with pure CSS classes
|
|
362
|
+
</h3>
|
|
363
|
+
<p>
|
|
364
|
+
You've clicked the burger
|
|
365
|
+
{" "}
|
|
366
|
+
<strong>
|
|
367
|
+
{count}
|
|
368
|
+
</strong>
|
|
369
|
+
{" "}
|
|
370
|
+
times.
|
|
371
|
+
</p>
|
|
372
|
+
<button
|
|
373
|
+
onClick={lambda e: any -> None { count = count + 1;}}
|
|
374
|
+
style={{
|
|
375
|
+
"padding": "0.6rem 1.4rem",
|
|
376
|
+
"fontSize": "1rem",
|
|
377
|
+
"backgroundColor": "#ff6b35",
|
|
378
|
+
"color": "white",
|
|
379
|
+
"border": "none",
|
|
380
|
+
"borderRadius": "6px",
|
|
381
|
+
"cursor": "pointer",
|
|
382
|
+
"boxShadow": "0 2px 4px rgba(0,0,0,0.2)"
|
|
383
|
+
}}
|
|
384
|
+
>
|
|
385
|
+
Click the Burger! 🍔
|
|
386
|
+
</button>
|
|
387
|
+
</div>
|
|
388
|
+
<div style={{"marginTop": "2rem"}}>
|
|
389
|
+
<h3>
|
|
390
|
+
Backend Walkers
|
|
391
|
+
</h3>
|
|
392
|
+
<p>
|
|
393
|
+
Basic example walkers:
|
|
394
|
+
{" "}
|
|
395
|
+
<code>
|
|
396
|
+
ping_server
|
|
397
|
+
</code>
|
|
398
|
+
{" "}
|
|
399
|
+
and
|
|
400
|
+
{" "}
|
|
401
|
+
<code>
|
|
402
|
+
get_server_message
|
|
403
|
+
</code>
|
|
404
|
+
</p>
|
|
405
|
+
<button
|
|
406
|
+
onClick={lambda e: any -> None { handlePing();}}
|
|
407
|
+
style={{
|
|
408
|
+
"padding": "0.5rem 1.2rem",
|
|
409
|
+
"marginRight": "0.75rem",
|
|
410
|
+
"backgroundColor": "#3b82f6",
|
|
411
|
+
"color": "white",
|
|
412
|
+
"border": "none",
|
|
413
|
+
"borderRadius": "6px",
|
|
414
|
+
"cursor": "pointer"
|
|
415
|
+
}}
|
|
416
|
+
>
|
|
417
|
+
Ping Backend
|
|
418
|
+
</button>
|
|
419
|
+
<button
|
|
420
|
+
onClick={lambda e: any -> None { handleCreateSampleTodo();}}
|
|
421
|
+
style={{
|
|
422
|
+
"padding": "0.5rem 1.2rem",
|
|
423
|
+
"backgroundColor": "#10b981",
|
|
424
|
+
"color": "white",
|
|
425
|
+
"border": "none",
|
|
426
|
+
"borderRadius": "6px",
|
|
427
|
+
"cursor": "pointer"
|
|
428
|
+
}}
|
|
429
|
+
>
|
|
430
|
+
Create Sample Todo
|
|
431
|
+
</button>
|
|
432
|
+
{pingResult
|
|
433
|
+
and (
|
|
434
|
+
<span style={{"marginLeft": "0.5rem", "color": "#374151"}}>
|
|
435
|
+
Result:
|
|
436
|
+
{" "}
|
|
437
|
+
<code>
|
|
438
|
+
{pingResult}
|
|
439
|
+
</code>
|
|
440
|
+
</span>
|
|
441
|
+
)}
|
|
442
|
+
{serverMessage
|
|
443
|
+
and (
|
|
444
|
+
<p style={{"marginTop": "0.75rem", "color": "#374151"}}>
|
|
445
|
+
Message:
|
|
446
|
+
{" "}
|
|
447
|
+
<code>
|
|
448
|
+
{serverMessage}
|
|
449
|
+
</code>
|
|
450
|
+
</p>
|
|
451
|
+
)}
|
|
452
|
+
{lastTodoMessage
|
|
453
|
+
and (
|
|
454
|
+
<p style={{"marginTop": "0.5rem", "color": "#111827"}}>
|
|
455
|
+
{lastTodoMessage}
|
|
456
|
+
</p>
|
|
457
|
+
)}
|
|
458
|
+
</div>
|
|
459
|
+
<div style={{"marginTop": "2rem"}}>
|
|
460
|
+
<h3>
|
|
461
|
+
Web Worker
|
|
462
|
+
</h3>
|
|
463
|
+
<p>
|
|
464
|
+
This demonstrates how to communicate with a
|
|
465
|
+
{" "}
|
|
466
|
+
<strong>
|
|
467
|
+
Python backend worker
|
|
468
|
+
</strong>
|
|
469
|
+
{" "}
|
|
470
|
+
using Web Workers for asynchronous processing.
|
|
471
|
+
</p>
|
|
472
|
+
<p
|
|
473
|
+
style={{
|
|
474
|
+
"fontSize": "0.9rem",
|
|
475
|
+
"color": "#666",
|
|
476
|
+
"marginTop": "0.5rem"
|
|
477
|
+
}}
|
|
478
|
+
>
|
|
479
|
+
File:
|
|
480
|
+
{" "}
|
|
481
|
+
<code>
|
|
482
|
+
worker.py
|
|
483
|
+
</code>
|
|
484
|
+
{" "}
|
|
485
|
+
— Runs in a separate thread to avoid blocking the UI.
|
|
486
|
+
</p>
|
|
487
|
+
<button
|
|
488
|
+
onClick={lambda -> None { handleClick();}}
|
|
489
|
+
style={{
|
|
490
|
+
"padding": "0.5rem 1.2rem",
|
|
491
|
+
"marginRight": "0.75rem",
|
|
492
|
+
"backgroundColor": "#d73bf6ff",
|
|
493
|
+
"color": "white",
|
|
494
|
+
"border": "none",
|
|
495
|
+
"borderRadius": "6px",
|
|
496
|
+
"cursor": "pointer"
|
|
497
|
+
}}
|
|
498
|
+
>
|
|
499
|
+
Call Python Worker
|
|
500
|
+
</button>
|
|
501
|
+
{message
|
|
502
|
+
&& (
|
|
503
|
+
<p style={{marginTop: "1rem", fontWeight: "bold"}}>
|
|
504
|
+
{message}
|
|
505
|
+
</p>
|
|
506
|
+
)}
|
|
507
|
+
</div>
|
|
508
|
+
</div>;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
def:pub app -> any {
|
|
512
|
+
return
|
|
513
|
+
<Router>
|
|
514
|
+
<div style={{"fontFamily": "system-ui, -apple-system, sans-serif"}}>
|
|
515
|
+
<Navigation />
|
|
516
|
+
<div
|
|
517
|
+
style={{
|
|
518
|
+
"maxWidth": "960px",
|
|
519
|
+
"margin": "0 auto",
|
|
520
|
+
"padding": "0 1rem 3rem 1rem"
|
|
521
|
+
}}
|
|
522
|
+
>
|
|
523
|
+
<Routes>
|
|
524
|
+
<Route path="/" element={<HomePage />} />
|
|
525
|
+
<Route path="/login" element={<LoginPage />} />
|
|
526
|
+
<Route path="/signup" element={<SignupPage />} />
|
|
527
|
+
<Route path="/nested" element={<NestedImportsDemo />} />
|
|
528
|
+
<Route path="/features-test" element={<FeaturesTest />} />
|
|
529
|
+
<Route path="/landing" element={<LandingPage />} />
|
|
530
|
+
<Route
|
|
531
|
+
path="/budget-planner"
|
|
532
|
+
element={<BudgetProvider>
|
|
533
|
+
<BudgetPlanner />
|
|
534
|
+
</BudgetProvider>}
|
|
535
|
+
/>
|
|
536
|
+
<Route path="*" element={<NotFound />} />
|
|
537
|
+
</Routes>
|
|
538
|
+
</div>
|
|
539
|
+
</div>
|
|
540
|
+
</Router>;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
# This file is intentionally kept empty to demonstrate the separation of concerns
|
|
3
3
|
# where UI logic resides in .cl.jac files and backend walker logic in app.jac
|
|
4
4
|
|
|
5
|
-
# All walker implementations for this feature are in
|
|
5
|
+
# All walker implementations for this feature are in main.jac
|
|
6
6
|
# This demonstrates that you can have separate .jac files for different purposes
|
|
7
7
|
# Features Test - Backend Walkers
|
|
8
8
|
# This file demonstrates walker functionality for testing various JAC features
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
import from datetime {
|
|
10
|
+
datetime,
|
|
11
|
+
timedelta
|
|
12
|
+
}
|
|
11
13
|
|
|
12
14
|
# Node definition for storing test data
|
|
13
15
|
node TestData {
|
|
14
|
-
has message: str
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
has message: str,
|
|
17
|
+
count: int = 0,
|
|
18
|
+
created_at: str = "";
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
# Walker: Create test data
|
|
@@ -106,12 +108,14 @@ walker process_complex_data {
|
|
|
106
108
|
can process with `root entry {
|
|
107
109
|
processed = [];
|
|
108
110
|
for item in self.items {
|
|
109
|
-
processed.append(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
processed.append(
|
|
112
|
+
{
|
|
113
|
+
"id": item.get("id", 0),
|
|
114
|
+
"name": item.get("name", "").upper(),
|
|
115
|
+
"value": item.get("value", 0) * 2,
|
|
116
|
+
"processed_at": datetime.now().strftime("%H:%M:%S")
|
|
117
|
+
}
|
|
118
|
+
);
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
result = {
|
|
@@ -124,3 +128,13 @@ walker process_complex_data {
|
|
|
124
128
|
report result;
|
|
125
129
|
}
|
|
126
130
|
}
|
|
131
|
+
|
|
132
|
+
# Re-export client components from the standalone client module
|
|
133
|
+
cl {
|
|
134
|
+
import from .budget_planner_ui { BudgetPlanner as BudgetPlannerUI }
|
|
135
|
+
|
|
136
|
+
def:pub BudgetPlanner -> any {
|
|
137
|
+
return
|
|
138
|
+
<BudgetPlannerUI />;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
# This file is intentionally kept empty to demonstrate the separation of concerns
|
|
3
3
|
# where UI logic resides in .cl.jac files and backend walker logic in app.jac
|
|
4
4
|
|
|
5
|
-
# All walker implementations for this feature are in
|
|
5
|
+
# All walker implementations for this feature are in main.jac
|
|
6
6
|
# This demonstrates that you can have separate .jac files for different purposes
|
|
7
7
|
# Features Test - Backend Walkers
|
|
8
8
|
# This file demonstrates walker functionality for testing various JAC features
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
import from datetime {
|
|
10
|
+
datetime,
|
|
11
|
+
timedelta
|
|
12
|
+
}
|
|
11
13
|
|
|
12
14
|
# Node definition for storing test data
|
|
13
15
|
node TestData {
|
|
14
|
-
has message: str
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
has message: str,
|
|
17
|
+
count: int = 0,
|
|
18
|
+
created_at: str = "";
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
# Walker: Create test data
|
|
@@ -106,12 +108,14 @@ walker process_complex_data {
|
|
|
106
108
|
can process with `root entry {
|
|
107
109
|
processed = [];
|
|
108
110
|
for item in self.items {
|
|
109
|
-
processed.append(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
processed.append(
|
|
112
|
+
{
|
|
113
|
+
"id": item.get("id", 0),
|
|
114
|
+
"name": item.get("name", "").upper(),
|
|
115
|
+
"value": item.get("value", 0) * 2,
|
|
116
|
+
"processed_at": datetime.now().strftime("%H:%M:%S")
|
|
117
|
+
}
|
|
118
|
+
);
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
result = {
|
|
@@ -124,3 +128,30 @@ walker process_complex_data {
|
|
|
124
128
|
report result;
|
|
125
129
|
}
|
|
126
130
|
}
|
|
131
|
+
|
|
132
|
+
# Re-export client components from the standalone client module
|
|
133
|
+
cl {
|
|
134
|
+
import from .features_test_ui {
|
|
135
|
+
FeaturesTest as FeaturesTestUI,
|
|
136
|
+
TestButton as TestButtonUI,
|
|
137
|
+
TestCard as TestCardUI,
|
|
138
|
+
ResultDisplay as ResultDisplayUI
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
def:pub FeaturesTest -> any {
|
|
142
|
+
return
|
|
143
|
+
<FeaturesTestUI />;
|
|
144
|
+
}
|
|
145
|
+
def:pub TestButton(text: str, onClick: any, variant: str) -> any {
|
|
146
|
+
return
|
|
147
|
+
<TestButtonUI text={text} onClick={onClick} variant={variant} />;
|
|
148
|
+
}
|
|
149
|
+
def:pub TestCard(title: str, children: any, color: str) -> any {
|
|
150
|
+
return
|
|
151
|
+
<TestCardUI title={title} children={children} color={color} />;
|
|
152
|
+
}
|
|
153
|
+
def:pub ResultDisplay(data: any, label: str) -> any {
|
|
154
|
+
return
|
|
155
|
+
<ResultDisplayUI data={data} label={label} />;
|
|
156
|
+
}
|
|
157
|
+
}
|