jac-client 0.2.2__py3-none-any.whl → 0.2.4__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.
Files changed (176) hide show
  1. jac_client/examples/all-in-one/assets/workers/worker.py +5 -0
  2. jac_client/tests/conftest.py +281 -0
  3. jac_client/tests/test_cli.py +755 -0
  4. jac_client/tests/test_it.py +347 -67
  5. {jac_client-0.2.2.dist-info → jac_client-0.2.4.dist-info}/METADATA +30 -24
  6. jac_client-0.2.4.dist-info/RECORD +10 -0
  7. {jac_client-0.2.2.dist-info → jac_client-0.2.4.dist-info}/WHEEL +2 -1
  8. jac_client-0.2.4.dist-info/entry_points.txt +4 -0
  9. jac_client-0.2.4.dist-info/top_level.txt +1 -0
  10. jac_client/docs/README.md +0 -689
  11. jac_client/docs/advanced-state.md +0 -1265
  12. jac_client/docs/asset-serving/intro.md +0 -209
  13. jac_client/docs/assets/pipe_line-v2.svg +0 -32
  14. jac_client/docs/assets/pipe_line.png +0 -0
  15. jac_client/docs/file-system/app.jac.md +0 -121
  16. jac_client/docs/file-system/backend-frontend.md +0 -217
  17. jac_client/docs/file-system/intro.md +0 -72
  18. jac_client/docs/file-system/nested-imports.md +0 -348
  19. jac_client/docs/guide-example/intro.md +0 -115
  20. jac_client/docs/guide-example/step-01-setup.md +0 -270
  21. jac_client/docs/guide-example/step-02-components.md +0 -416
  22. jac_client/docs/guide-example/step-03-styling.md +0 -478
  23. jac_client/docs/guide-example/step-04-todo-ui.md +0 -477
  24. jac_client/docs/guide-example/step-05-local-state.md +0 -530
  25. jac_client/docs/guide-example/step-06-events.md +0 -749
  26. jac_client/docs/guide-example/step-07-effects.md +0 -468
  27. jac_client/docs/guide-example/step-08-walkers.md +0 -534
  28. jac_client/docs/guide-example/step-09-authentication.md +0 -586
  29. jac_client/docs/guide-example/step-10-routing.md +0 -539
  30. jac_client/docs/guide-example/step-11-final.md +0 -963
  31. jac_client/docs/imports.md +0 -1141
  32. jac_client/docs/lifecycle-hooks.md +0 -773
  33. jac_client/docs/routing.md +0 -659
  34. jac_client/docs/styling/intro.md +0 -249
  35. jac_client/docs/styling/js-styling.md +0 -367
  36. jac_client/docs/styling/material-ui.md +0 -341
  37. jac_client/docs/styling/pure-css.md +0 -299
  38. jac_client/docs/styling/sass.md +0 -403
  39. jac_client/docs/styling/styled-components.md +0 -395
  40. jac_client/docs/styling/tailwind.md +0 -298
  41. jac_client/examples/all-in-one/.babelrc +0 -9
  42. jac_client/examples/all-in-one/README.md +0 -16
  43. jac_client/examples/all-in-one/app.jac +0 -426
  44. jac_client/examples/all-in-one/assets/burger.png +0 -0
  45. jac_client/examples/all-in-one/button.jac +0 -7
  46. jac_client/examples/all-in-one/components/button.jac +0 -7
  47. jac_client/examples/all-in-one/package.json +0 -29
  48. jac_client/examples/all-in-one/styles.css +0 -26
  49. jac_client/examples/all-in-one/vite.config.js +0 -28
  50. jac_client/examples/asset-serving/css-with-image/.babelrc +0 -9
  51. jac_client/examples/asset-serving/css-with-image/README.md +0 -91
  52. jac_client/examples/asset-serving/css-with-image/app.jac +0 -88
  53. jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
  54. jac_client/examples/asset-serving/css-with-image/package.json +0 -28
  55. jac_client/examples/asset-serving/css-with-image/styles.css +0 -26
  56. jac_client/examples/asset-serving/css-with-image/vite.config.js +0 -28
  57. jac_client/examples/asset-serving/image-asset/.babelrc +0 -9
  58. jac_client/examples/asset-serving/image-asset/README.md +0 -119
  59. jac_client/examples/asset-serving/image-asset/app.jac +0 -55
  60. jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
  61. jac_client/examples/asset-serving/image-asset/package.json +0 -28
  62. jac_client/examples/asset-serving/image-asset/styles.css +0 -26
  63. jac_client/examples/asset-serving/image-asset/vite.config.js +0 -28
  64. jac_client/examples/asset-serving/import-alias/.babelrc +0 -9
  65. jac_client/examples/asset-serving/import-alias/README.md +0 -83
  66. jac_client/examples/asset-serving/import-alias/app.jac +0 -111
  67. jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
  68. jac_client/examples/asset-serving/import-alias/package.json +0 -28
  69. jac_client/examples/asset-serving/import-alias/vite.config.js +0 -28
  70. jac_client/examples/basic/.babelrc +0 -9
  71. jac_client/examples/basic/README.md +0 -16
  72. jac_client/examples/basic/app.jac +0 -21
  73. jac_client/examples/basic/package.json +0 -27
  74. jac_client/examples/basic/vite.config.js +0 -27
  75. jac_client/examples/basic-auth/.babelrc +0 -9
  76. jac_client/examples/basic-auth/README.md +0 -16
  77. jac_client/examples/basic-auth/app.jac +0 -308
  78. jac_client/examples/basic-auth/package.json +0 -27
  79. jac_client/examples/basic-auth/vite.config.js +0 -27
  80. jac_client/examples/basic-auth-with-router/.babelrc +0 -9
  81. jac_client/examples/basic-auth-with-router/README.md +0 -60
  82. jac_client/examples/basic-auth-with-router/app.jac +0 -464
  83. jac_client/examples/basic-auth-with-router/package.json +0 -28
  84. jac_client/examples/basic-auth-with-router/vite.config.js +0 -27
  85. jac_client/examples/basic-full-stack/.babelrc +0 -9
  86. jac_client/examples/basic-full-stack/README.md +0 -18
  87. jac_client/examples/basic-full-stack/app.jac +0 -320
  88. jac_client/examples/basic-full-stack/package.json +0 -28
  89. jac_client/examples/basic-full-stack/vite.config.js +0 -27
  90. jac_client/examples/css-styling/js-styling/.babelrc +0 -9
  91. jac_client/examples/css-styling/js-styling/README.md +0 -183
  92. jac_client/examples/css-styling/js-styling/app.jac +0 -84
  93. jac_client/examples/css-styling/js-styling/package.json +0 -28
  94. jac_client/examples/css-styling/js-styling/styles.js +0 -100
  95. jac_client/examples/css-styling/js-styling/vite.config.js +0 -27
  96. jac_client/examples/css-styling/material-ui/.babelrc +0 -9
  97. jac_client/examples/css-styling/material-ui/README.md +0 -16
  98. jac_client/examples/css-styling/material-ui/app.jac +0 -122
  99. jac_client/examples/css-styling/material-ui/package.json +0 -32
  100. jac_client/examples/css-styling/material-ui/vite.config.js +0 -27
  101. jac_client/examples/css-styling/pure-css/.babelrc +0 -9
  102. jac_client/examples/css-styling/pure-css/README.md +0 -16
  103. jac_client/examples/css-styling/pure-css/app.jac +0 -64
  104. jac_client/examples/css-styling/pure-css/package.json +0 -28
  105. jac_client/examples/css-styling/pure-css/styles.css +0 -111
  106. jac_client/examples/css-styling/pure-css/vite.config.js +0 -27
  107. jac_client/examples/css-styling/sass-example/.babelrc +0 -9
  108. jac_client/examples/css-styling/sass-example/README.md +0 -16
  109. jac_client/examples/css-styling/sass-example/app.jac +0 -64
  110. jac_client/examples/css-styling/sass-example/package.json +0 -29
  111. jac_client/examples/css-styling/sass-example/styles.scss +0 -153
  112. jac_client/examples/css-styling/sass-example/vite.config.js +0 -27
  113. jac_client/examples/css-styling/styled-components/.babelrc +0 -9
  114. jac_client/examples/css-styling/styled-components/README.md +0 -16
  115. jac_client/examples/css-styling/styled-components/app.jac +0 -71
  116. jac_client/examples/css-styling/styled-components/package.json +0 -29
  117. jac_client/examples/css-styling/styled-components/styled.js +0 -90
  118. jac_client/examples/css-styling/styled-components/vite.config.js +0 -27
  119. jac_client/examples/css-styling/tailwind-example/.babelrc +0 -9
  120. jac_client/examples/css-styling/tailwind-example/README.md +0 -16
  121. jac_client/examples/css-styling/tailwind-example/app.jac +0 -63
  122. jac_client/examples/css-styling/tailwind-example/global.css +0 -1
  123. jac_client/examples/css-styling/tailwind-example/package.json +0 -30
  124. jac_client/examples/css-styling/tailwind-example/vite.config.js +0 -29
  125. jac_client/examples/full-stack-with-auth/.babelrc +0 -9
  126. jac_client/examples/full-stack-with-auth/README.md +0 -16
  127. jac_client/examples/full-stack-with-auth/app.jac +0 -722
  128. jac_client/examples/full-stack-with-auth/package.json +0 -28
  129. jac_client/examples/full-stack-with-auth/vite.config.js +0 -29
  130. jac_client/examples/little-x/app.jac +0 -724
  131. jac_client/examples/little-x/package.json +0 -23
  132. jac_client/examples/little-x/submit-button.jac +0 -8
  133. jac_client/examples/nested-folders/nested-advance/.babelrc +0 -9
  134. jac_client/examples/nested-folders/nested-advance/ButtonRoot.jac +0 -11
  135. jac_client/examples/nested-folders/nested-advance/README.md +0 -77
  136. jac_client/examples/nested-folders/nested-advance/app.jac +0 -35
  137. jac_client/examples/nested-folders/nested-advance/level1/ButtonSecondL.jac +0 -19
  138. jac_client/examples/nested-folders/nested-advance/level1/Card.jac +0 -43
  139. jac_client/examples/nested-folders/nested-advance/level1/level2/ButtonThirdL.jac +0 -25
  140. jac_client/examples/nested-folders/nested-advance/package.json +0 -29
  141. jac_client/examples/nested-folders/nested-advance/vite.config.js +0 -28
  142. jac_client/examples/nested-folders/nested-basic/.babelrc +0 -9
  143. jac_client/examples/nested-folders/nested-basic/README.md +0 -183
  144. jac_client/examples/nested-folders/nested-basic/app.jac +0 -13
  145. jac_client/examples/nested-folders/nested-basic/app.js +0 -7
  146. jac_client/examples/nested-folders/nested-basic/button.jac +0 -7
  147. jac_client/examples/nested-folders/nested-basic/components/button.jac +0 -7
  148. jac_client/examples/nested-folders/nested-basic/package.json +0 -28
  149. jac_client/examples/nested-folders/nested-basic/vite.config.js +0 -27
  150. jac_client/examples/with-router/.babelrc +0 -9
  151. jac_client/examples/with-router/README.md +0 -17
  152. jac_client/examples/with-router/app.jac +0 -323
  153. jac_client/examples/with-router/package.json +0 -28
  154. jac_client/examples/with-router/vite.config.js +0 -27
  155. jac_client/plugin/cli.py +0 -244
  156. jac_client/plugin/client.py +0 -152
  157. jac_client/plugin/client_runtime.jac +0 -234
  158. jac_client/plugin/vite_client_bundle.py +0 -503
  159. jac_client/tests/fixtures/basic-app/app.jac +0 -23
  160. jac_client/tests/fixtures/cl_file/app.cl.jac +0 -48
  161. jac_client/tests/fixtures/cl_file/app.jac +0 -15
  162. jac_client/tests/fixtures/client_app_with_antd/app.jac +0 -34
  163. jac_client/tests/fixtures/js_import/app.jac +0 -34
  164. jac_client/tests/fixtures/js_import/utils.js +0 -21
  165. jac_client/tests/fixtures/package-lock.json +0 -329
  166. jac_client/tests/fixtures/package.json +0 -11
  167. jac_client/tests/fixtures/relative_import/app.jac +0 -11
  168. jac_client/tests/fixtures/relative_import/button.jac +0 -7
  169. jac_client/tests/fixtures/spawn_test/app.jac +0 -129
  170. jac_client/tests/fixtures/test_fragments_spread/app.jac +0 -67
  171. jac_client/tests/test_asset_examples.py +0 -322
  172. jac_client/tests/test_cl.py +0 -530
  173. jac_client/tests/test_create_jac_app.py +0 -131
  174. jac_client/tests/test_nested_file.py +0 -374
  175. jac_client-0.2.2.dist-info/RECORD +0 -171
  176. jac_client-0.2.2.dist-info/entry_points.txt +0 -4
@@ -1,963 +0,0 @@
1
- # Step 11: Final Integration - Complete App
2
-
3
- > ** Quick Tip:** Each step has two parts. **Part 1** shows you what to build. **Part 2** explains why it works. Want to just build? Skip all Part 2 sections!
4
-
5
- Congratulations! In this final step, you'll see the complete, production-ready todo application with all features integrated!
6
-
7
- ---
8
-
9
- ## Part 1: The Complete App
10
-
11
- ### Complete `app.jac` File
12
-
13
- Here's your entire application in one file. This is the exact app from the `full-stack-with-auth` example:
14
-
15
- ```jac
16
- # Full Stack Todo App with Auth and React Router
17
- cl import from react {
18
- useState,
19
- useEffect
20
- }
21
- cl import from "@jac-client/utils" {
22
- Router,
23
- Routes,
24
- Route,
25
- Link,
26
- Navigate,
27
- useNavigate,
28
- jacSignup,
29
- jacLogin,
30
- jacLogout,
31
- jacIsLoggedIn
32
- }
33
-
34
- # Backend - Todo Node
35
- node Todo {
36
- has text: str;
37
- has done: bool = False;
38
- }
39
-
40
- # Backend - Walkers
41
- walker create_todo {
42
- has text: str;
43
-
44
- can create with `root entry {
45
- new_todo = here ++> Todo(text=self.text);
46
- report new_todo ;
47
- }
48
- }
49
-
50
- walker read_todos {
51
- can read with `root entry {
52
- visit [-->(`?Todo)];
53
- }
54
-
55
- can report_todos with Todo entry {
56
- report here ;
57
- }
58
- }
59
-
60
- walker toggle_todo {
61
- can toggle with Todo entry {
62
- here.done = not here.done;
63
- report here ;
64
- }
65
- }
66
-
67
- # Frontend Components
68
- cl {
69
- # Navigation
70
- def Navigation() -> any {
71
- let isLoggedIn = jacIsLoggedIn();
72
- let navigate = useNavigate();
73
-
74
- def handleLogout(e: any) -> None {
75
- e.preventDefault();
76
- jacLogout();
77
- navigate("/login");
78
- }
79
-
80
- if isLoggedIn {
81
- return <nav
82
- style={{
83
- "padding": "12px 24px",
84
- "background": "#3b82f6",
85
- "color": "#ffffff",
86
- "display": "flex",
87
- "justifyContent": "space-between"
88
- }}
89
- >
90
- <div
91
- style={{"fontWeight": "600"}}
92
- >
93
- Todo App
94
- </div>
95
- <div
96
- style={{"display": "flex", "gap": "16px"}}
97
- >
98
- <Link
99
- to="/todos"
100
- style={{"color": "#ffffff", "textDecoration": "none"}}
101
- >
102
- Todos
103
- </Link>
104
- <button
105
- onClick={handleLogout}
106
- style={{
107
- "background": "none",
108
- "color": "#ffffff",
109
- "border": "1px solid #ffffff",
110
- "padding": "2px 10px",
111
- "borderRadius": "4px",
112
- "cursor": "pointer"
113
- }}
114
- >
115
- Logout
116
- </button>
117
- </div>
118
- </nav>;
119
- }
120
-
121
- return <nav
122
- style={{
123
- "padding": "12px 24px",
124
- "background": "#3b82f6",
125
- "color": "#ffffff",
126
- "display": "flex",
127
- "justifyContent": "space-between"
128
- }}
129
- >
130
- <div
131
- style={{"fontWeight": "600"}}
132
- >
133
- Todo App
134
- </div>
135
- <div
136
- style={{"display": "flex", "gap": "16px"}}
137
- >
138
- <Link
139
- to="/login"
140
- style={{"color": "#ffffff", "textDecoration": "none"}}
141
- >
142
- Login
143
- </Link>
144
- <Link
145
- to="/signup"
146
- style={{"color": "#ffffff", "textDecoration": "none"}}
147
- >
148
- Sign Up
149
- </Link>
150
- </div>
151
- </nav>;
152
- }
153
-
154
- # Login Page
155
- def LoginPage() -> any {
156
- let [username, setUsername] = useState("");
157
- let [password, setPassword] = useState("");
158
- let [error, setError] = useState("");
159
- let navigate = useNavigate();
160
-
161
- async def handleLogin(e: any) -> None {
162
- e.preventDefault();
163
- setError("");
164
- if not username or not password {
165
- setError("Please fill in all fields");
166
- return;
167
- }
168
- success = await jacLogin(username, password);
169
- if success {
170
- navigate("/todos");
171
- } else {
172
- setError("Invalid credentials");
173
- }
174
- }
175
-
176
- def handleUsernameChange(e: any) -> None {
177
- setUsername(e.target.value);
178
- }
179
-
180
- def handlePasswordChange(e: any) -> None {
181
- setPassword(e.target.value);
182
- }
183
-
184
- let errorDisplay = None;
185
- if error {
186
- errorDisplay = <div
187
- style={{"color": "#dc2626", "fontSize": "14px", "marginBottom": "10px"}}
188
- >
189
- {error}
190
- </div>;
191
- }
192
-
193
- return <div
194
- style={{
195
- "minHeight": "calc(100vh - 48px)",
196
- "display": "flex",
197
- "alignItems": "center",
198
- "justifyContent": "center",
199
- "background": "#f5f5f5"
200
- }}
201
- >
202
- <div
203
- style={{
204
- "background": "#ffffff",
205
- "padding": "30px",
206
- "borderRadius": "8px",
207
- "width": "280px",
208
- "boxShadow": "0 2px 4px rgba(0,0,0,0.1)"
209
- }}
210
- >
211
- <h2
212
- style={{"marginBottom": "20px"}}
213
- >
214
- Login
215
- </h2>
216
- <form
217
- onSubmit={handleLogin}
218
- >
219
- <input
220
- type="text"
221
- value={username}
222
- onChange={handleUsernameChange}
223
- placeholder="Username"
224
- style={{
225
- "width": "100%",
226
- "padding": "8px",
227
- "marginBottom": "10px",
228
- "border": "1px solid #ddd",
229
- "borderRadius": "4px",
230
- "boxSizing": "border-box"
231
- }}
232
- />
233
- <input
234
- type="password"
235
- value={password}
236
- onChange={handlePasswordChange}
237
- placeholder="Password"
238
- style={{
239
- "width": "100%",
240
- "padding": "8px",
241
- "marginBottom": "10px",
242
- "border": "1px solid #ddd",
243
- "borderRadius": "4px",
244
- "boxSizing": "border-box"
245
- }}
246
- />
247
- {errorDisplay}
248
- <button
249
- type="submit"
250
- style={{
251
- "width": "100%",
252
- "padding": "8px",
253
- "background": "#3b82f6",
254
- "color": "#ffffff",
255
- "border": "none",
256
- "borderRadius": "4px",
257
- "cursor": "pointer",
258
- "fontWeight": "600"
259
- }}
260
- >
261
- Login
262
- </button>
263
- </form>
264
- <p
265
- style={{
266
- "textAlign": "center",
267
- "marginTop": "12px",
268
- "fontSize": "14px"
269
- }}
270
- >
271
- Need an account?
272
- <Link to="/signup">
273
- Sign up
274
- </Link>
275
- </p>
276
- </div>
277
- </div>;
278
- }
279
-
280
- # Signup Page
281
- def SignupPage() -> any {
282
- let [username, setUsername] = useState("");
283
- let [password, setPassword] = useState("");
284
- let [error, setError] = useState("");
285
- let navigate = useNavigate();
286
-
287
- async def handleSignup(e: any) -> None {
288
- e.preventDefault();
289
- setError("");
290
- if not username or not password {
291
- setError("Please fill in all fields");
292
- return;
293
- }
294
- result = await jacSignup(username, password);
295
- if result["success"] {
296
- navigate("/todos");
297
- } else {
298
- setError(result["error"] if result["error"] else "Signup failed");
299
- }
300
- }
301
-
302
- def handleUsernameChange(e: any) -> None {
303
- setUsername(e.target.value);
304
- }
305
-
306
- def handlePasswordChange(e: any) -> None {
307
- setPassword(e.target.value);
308
- }
309
-
310
- let errorDisplay = None;
311
- if error {
312
- errorDisplay = <div
313
- style={{"color": "#dc2626", "fontSize": "14px", "marginBottom": "10px"}}
314
- >
315
- {error}
316
- </div>;
317
- }
318
-
319
- return <div
320
- style={{
321
- "minHeight": "calc(100vh - 48px)",
322
- "display": "flex",
323
- "alignItems": "center",
324
- "justifyContent": "center",
325
- "background": "#f5f5f5"
326
- }}
327
- >
328
- <div
329
- style={{
330
- "background": "#ffffff",
331
- "padding": "30px",
332
- "borderRadius": "8px",
333
- "width": "280px",
334
- "boxShadow": "0 2px 4px rgba(0,0,0,0.1)"
335
- }}
336
- >
337
- <h2
338
- style={{"marginBottom": "20px"}}
339
- >
340
- Sign Up
341
- </h2>
342
- <form
343
- onSubmit={handleSignup}
344
- >
345
- <input
346
- type="text"
347
- value={username}
348
- onChange={handleUsernameChange}
349
- placeholder="Username"
350
- style={{
351
- "width": "100%",
352
- "padding": "8px",
353
- "marginBottom": "10px",
354
- "border": "1px solid #ddd",
355
- "borderRadius": "4px",
356
- "boxSizing": "border-box"
357
- }}
358
- />
359
- <input
360
- type="password"
361
- value={password}
362
- onChange={handlePasswordChange}
363
- placeholder="Password"
364
- style={{
365
- "width": "100%",
366
- "padding": "8px",
367
- "marginBottom": "10px",
368
- "border": "1px solid #ddd",
369
- "borderRadius": "4px",
370
- "boxSizing": "border-box"
371
- }}
372
- />
373
- {errorDisplay}
374
- <button
375
- type="submit"
376
- style={{
377
- "width": "100%",
378
- "padding": "8px",
379
- "background": "#3b82f6",
380
- "color": "#ffffff",
381
- "border": "none",
382
- "borderRadius": "4px",
383
- "cursor": "pointer",
384
- "fontWeight": "600"
385
- }}
386
- >
387
- Sign Up
388
- </button>
389
- </form>
390
- <p
391
- style={{
392
- "textAlign": "center",
393
- "marginTop": "12px",
394
- "fontSize": "14px"
395
- }}
396
- >
397
- Have an account?
398
- <Link to="/login">
399
- Login
400
- </Link>
401
- </p>
402
- </div>
403
- </div>;
404
- }
405
-
406
- # Todos Page (Protected)
407
- def TodosPage() -> any {
408
- # Check if user is logged in, redirect if not
409
- if not jacIsLoggedIn() {
410
- return <Navigate to="/login" />;
411
- }
412
-
413
- let [todos, setTodos] = useState([]);
414
- let [input, setInput] = useState("");
415
- let [filter, setFilter] = useState("all");
416
-
417
- # Load todos on mount
418
- useEffect(
419
- lambda -> None{ async def loadTodos() -> None {
420
- result = root spawn read_todos();
421
- setTodos(result.reports if result.reports else []);
422
- } loadTodos();} ,
423
- []
424
- );
425
-
426
- # Add todo
427
- async def addTodo() -> None {
428
- if not input.trim() {
429
- return;
430
- }
431
- result = root spawn create_todo(text=input.trim());
432
- setTodos(todos.concat([result.reports[0][0]]));
433
- setInput("");
434
- }
435
-
436
- # Toggle todo
437
- async def toggleTodo(id: any) -> None {
438
- id spawn toggle_todo();
439
- setTodos(
440
- todos.map(
441
- lambda todo: any -> any{
442
- if todo._jac_id == id {
443
- return {
444
- "_jac_id": todo._jac_id,
445
- "text": todo.text,
446
- "done": not todo.done
447
- };
448
- }
449
- return todo;
450
- }
451
- )
452
- );
453
- }
454
-
455
- # Delete todo
456
- async def deleteTodo(id: any) -> None {
457
- #id spawn delete_todo();
458
- setTodos(
459
- todos.filter(lambda todo: any -> bool{ return todo._jac_id != id; } )
460
- );
461
- }
462
-
463
- # Filter todos
464
- def getFilteredTodos() -> list {
465
- if filter == "active" {
466
- return todos.filter(
467
- lambda todo: any -> bool{ return not todo.done; }
468
- );
469
- } elif filter == "completed" {
470
- return todos.filter(lambda todo: any -> bool{ return todo.done; } );
471
- }
472
- return todos;
473
- }
474
-
475
- filteredTodos = getFilteredTodos();
476
- activeCount = todos.filter(
477
- lambda todo: any -> bool{ return not todo.done; }
478
- ).length;
479
-
480
- return <div
481
- style={{
482
- "maxWidth": "600px",
483
- "margin": "20px auto",
484
- "padding": "20px",
485
- "background": "#ffffff",
486
- "borderRadius": "8px",
487
- "boxShadow": "0 2px 4px rgba(0,0,0,0.1)"
488
- }}
489
- >
490
- <h1
491
- style={{"marginBottom": "20px"}}
492
- >
493
- My Todos
494
- </h1>
495
-
496
- # Add todo input
497
- <div style={{"display": "flex", "gap": "8px", "marginBottom": "16px"}}>
498
- <input
499
- type="text"
500
- value={input}
501
- onChange={lambda e: any -> None { setInput(e.target.value); }}
502
- onKeyPress={lambda e: any -> None {
503
- if e.key == "Enter" {
504
- addTodo();
505
- }
506
- }}
507
- placeholder="What needs to be done?"
508
- style={{
509
- "flex": "1",
510
- "padding": "8px",
511
- "border": "1px solid #ddd",
512
- "borderRadius": "4px"
513
- }}
514
- />
515
- <button
516
- onClick={addTodo}
517
- style={{
518
- "padding": "8px 16px",
519
- "background": "#3b82f6",
520
- "color": "#ffffff",
521
- "border": "none",
522
- "borderRadius": "4px",
523
- "cursor": "pointer",
524
- "fontWeight": "600"
525
- }}
526
- >
527
- Add
528
- </button>
529
- </div>
530
-
531
- # Filter buttons
532
- <div style={{"display": "flex", "gap": "8px", "marginBottom": "16px"}}>
533
- <button
534
- onClick={lambda -> None{ setFilter("all");} }
535
- style={{
536
- "padding": "6px 12px",
537
- "background": ("#3b82f6" if filter == "all" else "#e5e7eb"),
538
- "color": ("#ffffff" if filter == "all" else "#000000"),
539
- "border": "none",
540
- "borderRadius": "4px",
541
- "cursor": "pointer",
542
- "fontSize": "14px"
543
- }}
544
- >
545
- All
546
- </button>
547
- <button
548
- onClick={lambda -> None{ setFilter("active");} }
549
- style={{
550
- "padding": "6px 12px",
551
- "background": ("#3b82f6" if filter == "active" else "#e5e7eb"),
552
- "color": ("#ffffff" if filter == "active" else "#000000"),
553
- "border": "none",
554
- "borderRadius": "4px",
555
- "cursor": "pointer",
556
- "fontSize": "14px"
557
- }}
558
- >
559
- Active
560
- </button>
561
- <button
562
- onClick={lambda -> None{ setFilter("completed");} }
563
- style={{
564
- "padding": "6px 12px",
565
- "background": (
566
- "#3b82f6" if filter == "completed" else "#e5e7eb"
567
- ),
568
- "color": ("#ffffff" if filter == "completed" else "#000000"),
569
- "border": "none",
570
- "borderRadius": "4px",
571
- "cursor": "pointer",
572
- "fontSize": "14px"
573
- }}
574
- >
575
- Completed
576
- </button>
577
- </div>
578
-
579
- # Todo list
580
- <div>
581
- {(<div style={{"padding": "20px", "textAlign": "center", "color": "#999"}}>
582
- No todos yet. Add one above!
583
- </div>) if filteredTodos.length == 0 else (
584
- filteredTodos.map(lambda todo: any -> any {
585
- return <div
586
- key={todo._jac_id}
587
- style={{
588
- "display": "flex",
589
- "alignItems": "center",
590
- "gap": "10px",
591
- "padding": "10px",
592
- "borderBottom": "1px solid #e5e7eb"
593
- }}
594
- >
595
- <input
596
- type="checkbox"
597
- checked={todo.done}
598
- onChange={lambda -> None{ toggleTodo(todo._jac_id);} }
599
- style={{"cursor": "pointer"}}
600
- />
601
- <span
602
- style={{
603
- "flex": "1",
604
- "textDecoration": (
605
- "line-through" if todo.done else "none"
606
- ),
607
- "color": ("#999" if todo.done else "#000")
608
- }}
609
- >
610
- {todo.text}
611
- </span>
612
- <button
613
- onClick={lambda -> None{ deleteTodo(todo._jac_id);} }
614
- style={{
615
- "padding": "4px 8px",
616
- "background": "#ef4444",
617
- "color": "#ffffff",
618
- "border": "none",
619
- "borderRadius": "4px",
620
- "cursor": "pointer",
621
- "fontSize": "12px"
622
- }}
623
- >
624
- Delete
625
- </button>
626
- </div>;
627
- })
628
- )}
629
- </div>
630
-
631
- # Stats
632
- {(
633
- <div
634
- style={{
635
- "marginTop": "16px",
636
- "padding": "10px",
637
- "background": "#f9fafb",
638
- "borderRadius": "4px",
639
- "fontSize": "14px",
640
- "color": "#666"
641
- }}
642
- >
643
- {activeCount} {"item" if activeCount == 1 else "items"} left
644
- </div>
645
- )
646
- if todos.length > 0
647
- else None}
648
- </div>;
649
- }
650
-
651
- # Home/Landing Page - auto-redirect
652
- def HomePage() -> any {
653
- if jacIsLoggedIn() {
654
- return <Navigate to="/todos" />;
655
- }
656
- return <Navigate to="/login" />;
657
- }
658
-
659
- # Main App with React Router
660
- def app() -> any {
661
- return <Router>
662
- <div
663
- style={{"fontFamily": "system-ui, sans-serif"}}
664
- >
665
- <Navigation />
666
- <Routes>
667
- <Route
668
- path="/"
669
- element={<HomePage />}
670
- />
671
- <Route
672
- path="/login"
673
- element={<LoginPage />}
674
- />
675
- <Route
676
- path="/signup"
677
- element={<SignupPage />}
678
- />
679
- <Route
680
- path="/todos"
681
- element={<TodosPage />}
682
- />
683
- </Routes>
684
- </div>
685
- </Router>;
686
- }
687
- }
688
- ```
689
-
690
- ### Running the App
691
-
692
- 1. **Save the code** to `app.jac`
693
-
694
- 2. **Start the server:**
695
- ```bash
696
- jac serve app.jac
697
- ```
698
-
699
- 3. **Open in browser:**
700
- ```
701
- http://localhost:8000/page/app
702
- ```
703
-
704
- 4. **Test it out:**
705
- - Create an account (signup)
706
- - Login
707
- - Add some todos
708
- - Toggle them complete/incomplete
709
- - Filter (All/Active/Completed)
710
- - Delete todos
711
- - Logout and login again - your todos persist!
712
-
713
- ---
714
-
715
- ** You did it!** You've built a complete full-stack app. The rest of this page explains what you built and what to do next.
716
-
717
- ---
718
-
719
- ## Part 2: What You Built
720
-
721
- ### Features Checklist
722
-
723
- **Authentication:**
724
- - User signup
725
- - User login
726
- - Logout
727
- - Session persistence
728
- - Protected routes
729
-
730
- **Todo Management:**
731
- - Create todos
732
- - Mark as complete/incomplete
733
- - Delete todos
734
- - Filter by status (all/active/completed)
735
- - Item counter
736
- - Empty state handling
737
-
738
- **UI/UX:**
739
- - Responsive design
740
- - Modern styling
741
- - Form validation
742
- - Error handling
743
- - Loading states
744
- - Smooth navigation
745
-
746
- **Backend:**
747
- - Data persistence with walkers
748
- - User isolation (each user sees only their data)
749
- - Graph-based data structure
750
- - Automatic API endpoints
751
-
752
- ### Technology Stack
753
-
754
- **Frontend:**
755
- - React (via Jac's `cl` blocks)
756
- - React Router (for navigation)
757
- - Inline CSS styling
758
- - JSX syntax
759
-
760
- **Backend:**
761
- - Jac walkers (backend functions)
762
- - Jac nodes (data structures)
763
- - Graph database (automatic)
764
- - Built-in authentication
765
-
766
- **Architecture:**
767
- - Single-page application (SPA)
768
- - Client-side routing
769
- - RESTful-like walker calls
770
- - Full-stack in one language
771
-
772
- ### File Structure
773
-
774
- ```
775
- Your entire app:
776
- ├── app.jac (735 lines)
777
- ├── Backend (nodes + walkers)
778
- ├── Frontend (React components)
779
- └── Routes (navigation)
780
- ```
781
-
782
- That's it! Just one file!
783
-
784
- ### Code Organization
785
-
786
- ```
787
- app.jac
788
- ├── Backend Section
789
- │ ├── node Todo (data model)
790
- │ └── Walkers (create, read, toggle, delete)
791
-
792
- └── Frontend Section (cl block)
793
- ├── Navigation component
794
- ├── LoginPage component
795
- ├── SignupPage component
796
- ├── TodosPage component
797
- ├── HomePage component (redirects)
798
- └── app function (router setup)
799
- ```
800
-
801
- ---
802
-
803
- ## What's Next?
804
-
805
- You've completed the tutorial! Here are some ideas to continue learning:
806
-
807
- ### 1. Enhance Your App
808
-
809
- **Easy additions:**
810
- - Edit todo text
811
- - Add due dates
812
- - Priority levels (high/medium/low)
813
- - Todo categories/tags
814
- - Search functionality
815
-
816
- **Medium difficulty:**
817
- - Drag-and-drop reordering
818
- - Dark mode toggle
819
- - Keyboard shortcuts
820
- - Undo/redo
821
- - Export/import todos
822
-
823
- **Advanced features:**
824
- - Real-time collaboration
825
- - Recurring todos
826
- - Notifications
827
- - Attach files to todos
828
- - Share lists with others
829
-
830
- ### 2. Improve the UI
831
-
832
- **Styling:**
833
- - Add CSS animations
834
- - Use a CSS framework (Tailwind CSS)
835
- - Better mobile responsiveness
836
- - Custom color themes
837
- - Icons library (React Icons)
838
-
839
- **UX improvements:**
840
- - Smooth transitions
841
- - Better loading states
842
- - Toast notifications
843
- - Confirmation dialogs
844
- - Keyboard navigation
845
-
846
- ### 3. Deploy Your App
847
-
848
- **Deployment options:**
849
- - Jac Cloud (easiest)
850
- - Vercel
851
- - Netlify
852
- - Digital Ocean
853
- - AWS
854
-
855
- **Steps:**
856
- ```bash
857
- # Install Jac Cloud
858
- pip install jac-cloud
859
-
860
- # Deploy
861
- jac cloud deploy app.jac
862
-
863
- # Your app is now live!
864
- ```
865
-
866
- ### 4. Learn Advanced Jac Features
867
-
868
- **Explore:**
869
- - AI features with byLLM
870
- - Complex graph structures
871
- - Advanced walker patterns
872
- - Multi-file organization
873
- - Testing strategies
874
- - Performance optimization
875
-
876
- ### 5. Build Something New
877
-
878
- Apply what you learned:
879
- - Blog platform
880
- - E-commerce store
881
- - Social media app
882
- - Project management tool
883
- - Chat application
884
- - Portfolio website
885
-
886
- ---
887
-
888
- ## Resources
889
-
890
- **Official Documentation:**
891
- - [Jac Documentation](https://www.jac-lang.org)
892
- - [Jac Examples](https://github.com/Jaseci-Labs/jaclang)
893
- - [React Docs](https://react.dev) (underlying framework)
894
-
895
- **Community:**
896
- - Jac Discord/Forum
897
- - GitHub Issues
898
- - Stack Overflow (tag: jac-lang)
899
-
900
- **Tutorials:**
901
- - Jac AI Features
902
- - Advanced Graph Patterns
903
- - Deployment Guides
904
- - Best Practices
905
-
906
- ---
907
-
908
- ## What You Learned
909
-
910
- Looking back at all 11 steps:
911
-
912
- 1. Project setup and structure
913
- 2. Components and props
914
- 3. Styling with inline CSS
915
- 4. Building complex UIs
916
- 5. State management with useState
917
- 6. Event handlers
918
- 7. Side effects with useEffect
919
- 8. Backend with walkers and nodes
920
- 9. User authentication
921
- 10. Client-side routing
922
- 11. Complete full-stack integration
923
-
924
- **Key concepts mastered:**
925
- - Full-stack development in one language
926
- - React component patterns
927
- - State management
928
- - Graph-based data storage
929
- - Authentication and authorization
930
- - Client-side routing
931
- - Async/await patterns
932
- - Form handling
933
- - Error handling
934
-
935
- ---
936
-
937
- ## Congratulations!
938
-
939
- You built a **complete, production-ready full-stack application** from scratch!
940
-
941
- **What makes this special:**
942
- - **735 lines** of code (compared to 2000+ in traditional stacks)
943
- - **One language** (compared to 3-4: JavaScript, Python, SQL, HTML/CSS)
944
- - **One file** (compared to dozens of files)
945
- - **Zero configuration** (no webpack, babel, etc.)
946
- - **Built-in auth** (no OAuth setup needed)
947
- - **Automatic backend** (no Express/Flask setup)
948
-
949
- You're now ready to build amazing full-stack applications with Jac!
950
-
951
- ---
952
-
953
- ## Share Your Success!
954
-
955
- Built something cool? Share it:
956
- - Tag #JacLang on social media
957
- - Contribute to Jac examples
958
- - Write a blog post
959
- - Help others learn
960
-
961
- **Thank you for completing this tutorial!**
962
-
963
- Happy coding with Jac!