jac-client 0.2.0__py3-none-any.whl → 0.2.3__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 (154) hide show
  1. jac_client/docs/README.md +50 -20
  2. jac_client/docs/advanced-state.md +13 -14
  3. jac_client/docs/asset-serving/intro.md +209 -0
  4. jac_client/docs/assets/pipe_line-v2.svg +32 -0
  5. jac_client/docs/file-system/app.jac.md +121 -0
  6. jac_client/docs/file-system/backend-frontend.md +217 -0
  7. jac_client/docs/file-system/intro.md +72 -0
  8. jac_client/docs/file-system/nested-imports.md +348 -0
  9. jac_client/docs/guide-example/intro.md +11 -13
  10. jac_client/docs/guide-example/step-01-setup.md +30 -20
  11. jac_client/docs/guide-example/step-02-components.md +24 -24
  12. jac_client/docs/guide-example/step-03-styling.md +24 -24
  13. jac_client/docs/guide-example/step-04-todo-ui.md +17 -17
  14. jac_client/docs/guide-example/step-05-local-state.md +23 -23
  15. jac_client/docs/guide-example/step-06-events.md +23 -24
  16. jac_client/docs/guide-example/step-07-effects.md +27 -28
  17. jac_client/docs/guide-example/step-08-walkers.md +23 -23
  18. jac_client/docs/guide-example/step-09-authentication.md +18 -18
  19. jac_client/docs/guide-example/step-10-routing.md +20 -21
  20. jac_client/docs/guide-example/step-11-final.md +34 -35
  21. jac_client/docs/imports.md +4 -5
  22. jac_client/docs/lifecycle-hooks.md +12 -13
  23. jac_client/docs/routing.md +21 -22
  24. jac_client/docs/styling/intro.md +249 -0
  25. jac_client/docs/styling/js-styling.md +367 -0
  26. jac_client/docs/styling/material-ui.md +341 -0
  27. jac_client/docs/styling/pure-css.md +299 -0
  28. jac_client/docs/styling/sass.md +403 -0
  29. jac_client/docs/styling/styled-components.md +395 -0
  30. jac_client/docs/styling/tailwind.md +298 -0
  31. jac_client/examples/all-in-one/.babelrc +9 -0
  32. jac_client/examples/all-in-one/README.md +16 -0
  33. jac_client/examples/all-in-one/app.jac +426 -0
  34. jac_client/examples/all-in-one/assets/burger.png +0 -0
  35. jac_client/examples/all-in-one/button.jac +7 -0
  36. jac_client/examples/all-in-one/components/button.jac +7 -0
  37. jac_client/examples/all-in-one/package.json +29 -0
  38. jac_client/examples/all-in-one/styles.css +26 -0
  39. jac_client/examples/all-in-one/vite.config.js +28 -0
  40. jac_client/examples/asset-serving/css-with-image/.babelrc +9 -0
  41. jac_client/examples/asset-serving/css-with-image/README.md +91 -0
  42. jac_client/examples/asset-serving/css-with-image/app.jac +88 -0
  43. jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
  44. jac_client/examples/asset-serving/css-with-image/package.json +28 -0
  45. jac_client/examples/asset-serving/css-with-image/styles.css +26 -0
  46. jac_client/examples/asset-serving/css-with-image/vite.config.js +28 -0
  47. jac_client/examples/asset-serving/image-asset/.babelrc +9 -0
  48. jac_client/examples/asset-serving/image-asset/README.md +119 -0
  49. jac_client/examples/asset-serving/image-asset/app.jac +55 -0
  50. jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
  51. jac_client/examples/asset-serving/image-asset/package.json +28 -0
  52. jac_client/examples/asset-serving/image-asset/styles.css +26 -0
  53. jac_client/examples/asset-serving/image-asset/vite.config.js +28 -0
  54. jac_client/examples/asset-serving/import-alias/.babelrc +9 -0
  55. jac_client/examples/asset-serving/import-alias/README.md +83 -0
  56. jac_client/examples/asset-serving/import-alias/app.jac +111 -0
  57. jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
  58. jac_client/examples/asset-serving/import-alias/package.json +28 -0
  59. jac_client/examples/asset-serving/import-alias/vite.config.js +28 -0
  60. jac_client/examples/basic/app.jac +14 -9
  61. jac_client/examples/basic/package.json +1 -1
  62. jac_client/examples/basic/vite.config.js +0 -1
  63. jac_client/examples/basic-auth/package.json +1 -1
  64. jac_client/examples/basic-auth/vite.config.js +0 -1
  65. jac_client/examples/basic-auth-with-router/package.json +1 -1
  66. jac_client/examples/basic-auth-with-router/vite.config.js +0 -1
  67. jac_client/examples/basic-full-stack/package.json +1 -1
  68. jac_client/examples/basic-full-stack/vite.config.js +0 -1
  69. jac_client/examples/css-styling/js-styling/.babelrc +9 -0
  70. jac_client/examples/css-styling/js-styling/README.md +183 -0
  71. jac_client/examples/css-styling/js-styling/app.jac +84 -0
  72. jac_client/examples/css-styling/js-styling/package.json +28 -0
  73. jac_client/examples/css-styling/js-styling/styles.js +100 -0
  74. jac_client/examples/css-styling/js-styling/vite.config.js +27 -0
  75. jac_client/examples/css-styling/material-ui/.babelrc +9 -0
  76. jac_client/examples/css-styling/material-ui/README.md +16 -0
  77. jac_client/examples/css-styling/material-ui/app.jac +122 -0
  78. jac_client/examples/css-styling/material-ui/package.json +32 -0
  79. jac_client/examples/css-styling/material-ui/vite.config.js +27 -0
  80. jac_client/examples/css-styling/pure-css/.babelrc +9 -0
  81. jac_client/examples/css-styling/pure-css/README.md +16 -0
  82. jac_client/examples/css-styling/pure-css/app.jac +64 -0
  83. jac_client/examples/css-styling/pure-css/package.json +28 -0
  84. jac_client/examples/css-styling/pure-css/styles.css +111 -0
  85. jac_client/examples/css-styling/pure-css/vite.config.js +27 -0
  86. jac_client/examples/css-styling/sass-example/.babelrc +9 -0
  87. jac_client/examples/css-styling/sass-example/README.md +16 -0
  88. jac_client/examples/css-styling/sass-example/app.jac +64 -0
  89. jac_client/examples/css-styling/sass-example/package.json +29 -0
  90. jac_client/examples/css-styling/sass-example/styles.scss +153 -0
  91. jac_client/examples/css-styling/sass-example/vite.config.js +27 -0
  92. jac_client/examples/css-styling/styled-components/.babelrc +9 -0
  93. jac_client/examples/css-styling/styled-components/README.md +16 -0
  94. jac_client/examples/css-styling/styled-components/app.jac +71 -0
  95. jac_client/examples/css-styling/styled-components/package.json +29 -0
  96. jac_client/examples/css-styling/styled-components/styled.js +90 -0
  97. jac_client/examples/css-styling/styled-components/vite.config.js +27 -0
  98. jac_client/examples/css-styling/tailwind-example/.babelrc +9 -0
  99. jac_client/examples/css-styling/tailwind-example/README.md +16 -0
  100. jac_client/examples/css-styling/tailwind-example/app.jac +63 -0
  101. jac_client/examples/css-styling/tailwind-example/global.css +1 -0
  102. jac_client/examples/css-styling/tailwind-example/package.json +30 -0
  103. jac_client/examples/css-styling/tailwind-example/vite.config.js +29 -0
  104. jac_client/examples/full-stack-with-auth/app.jac +20 -33
  105. jac_client/examples/full-stack-with-auth/package.json +1 -1
  106. jac_client/examples/full-stack-with-auth/vite.config.js +0 -1
  107. jac_client/examples/little-x/app.jac +327 -218
  108. jac_client/examples/little-x/submit-button.jac +1 -1
  109. jac_client/examples/nested-folders/nested-advance/.babelrc +9 -0
  110. jac_client/examples/nested-folders/nested-advance/ButtonRoot.jac +11 -0
  111. jac_client/examples/nested-folders/nested-advance/README.md +77 -0
  112. jac_client/examples/nested-folders/nested-advance/app.jac +35 -0
  113. jac_client/examples/nested-folders/nested-advance/level1/ButtonSecondL.jac +19 -0
  114. jac_client/examples/nested-folders/nested-advance/level1/Card.jac +43 -0
  115. jac_client/examples/nested-folders/nested-advance/level1/level2/ButtonThirdL.jac +25 -0
  116. jac_client/examples/nested-folders/nested-advance/package.json +29 -0
  117. jac_client/examples/nested-folders/nested-advance/vite.config.js +28 -0
  118. jac_client/examples/nested-folders/nested-basic/.babelrc +9 -0
  119. jac_client/examples/nested-folders/nested-basic/README.md +183 -0
  120. jac_client/examples/nested-folders/nested-basic/app.jac +13 -0
  121. jac_client/examples/nested-folders/nested-basic/app.js +7 -0
  122. jac_client/examples/nested-folders/nested-basic/button.jac +7 -0
  123. jac_client/examples/nested-folders/nested-basic/components/button.jac +7 -0
  124. jac_client/examples/nested-folders/nested-basic/package.json +28 -0
  125. jac_client/examples/nested-folders/nested-basic/vite.config.js +27 -0
  126. jac_client/examples/with-router/app.jac +1 -1
  127. jac_client/examples/with-router/package.json +1 -1
  128. jac_client/examples/with-router/vite.config.js +0 -1
  129. jac_client/plugin/cli.py +7 -2
  130. jac_client/plugin/client.py +68 -5
  131. jac_client/plugin/client_runtime.jac +1 -1
  132. jac_client/plugin/vite_client_bundle.py +162 -14
  133. jac_client/tests/__init__.py +0 -1
  134. jac_client/tests/fixtures/basic-app/app.jac +7 -2
  135. jac_client/tests/fixtures/cl_file/app.cl.jac +48 -0
  136. jac_client/tests/fixtures/cl_file/app.jac +15 -0
  137. jac_client/tests/fixtures/client_app_with_antd/app.jac +14 -8
  138. jac_client/tests/fixtures/js_import/app.jac +19 -15
  139. jac_client/tests/fixtures/js_import/utils.js +0 -1
  140. jac_client/tests/fixtures/package.json +1 -1
  141. jac_client/tests/fixtures/relative_import/app.jac +4 -6
  142. jac_client/tests/fixtures/relative_import/button.jac +7 -6
  143. jac_client/tests/fixtures/spawn_test/app.jac +1 -5
  144. jac_client/tests/fixtures/test_fragments_spread/app.jac +24 -10
  145. jac_client/tests/test_asset_examples.py +322 -0
  146. jac_client/tests/test_cl.py +480 -426
  147. jac_client/tests/test_create_jac_app.py +125 -133
  148. jac_client/tests/test_it.py +329 -0
  149. jac_client/tests/test_nested_file.py +374 -0
  150. {jac_client-0.2.0.dist-info → jac_client-0.2.3.dist-info}/METADATA +11 -3
  151. jac_client-0.2.3.dist-info/RECORD +171 -0
  152. jac_client-0.2.0.dist-info/RECORD +0 -72
  153. {jac_client-0.2.0.dist-info → jac_client-0.2.3.dist-info}/WHEEL +0 -0
  154. {jac_client-0.2.0.dist-info → jac_client-0.2.3.dist-info}/entry_points.txt +0 -0
@@ -14,28 +14,25 @@ node Profile {
14
14
 
15
15
  can get with get_profile entry {
16
16
  follwers = [
17
- {"id" : jid(i) , "username" : i.username }
18
- for i in [self-->( ` ? Profile ) ]
17
+ {"id": jid(i), "username": i.username} for i in [self-->(`?Profile)]
19
18
  ];
20
- report {"user" : self , "followers" : follwers } ;
19
+ report {"user": self, "followers": follwers} ;
21
20
  }
22
21
 
23
22
  can follow with follow_request entry {
24
- current_profile = [root-->( ` ? Profile ) ];
23
+ current_profile = [root-->(`?Profile)];
25
24
  current_profile[0] +>: Follow() :+> self;
26
25
  report self ;
27
26
  }
28
27
 
29
28
  can un_follow with un_follow_request entry {
30
-
31
- current_profile = [root-->( ` ? Profile ) ];
32
- follow_edge = [edge current_profile[0]->:Follow :->self];
29
+ current_profile = [root-->(`?Profile)];
30
+ follow_edge = [edge current_profile[0]->:Follow:->self];
33
31
  del follow_edge[0] ;
34
32
  report self ;
35
33
  }
36
34
  }
37
35
 
38
-
39
36
  obj TweetInfo {
40
37
  has username: str;
41
38
  has id: str;
@@ -45,7 +42,6 @@ obj TweetInfo {
45
42
  has comments: list;
46
43
  }
47
44
 
48
-
49
45
  node Tweet {
50
46
  has content: str;
51
47
  has embedding: list;
@@ -62,20 +58,20 @@ node Tweet {
62
58
  }
63
59
 
64
60
  can like_tweet with like_tweet entry {
65
- current_profile = [root-->( ` ? Profile ) ];
61
+ current_profile = [root-->(`?Profile)];
66
62
  self +>: Like() :+> current_profile[0];
67
63
  report self ;
68
64
  }
69
65
 
70
66
  can remove_like with remove_like entry {
71
- current_profile = [root-->( ` ? Profile ) ];
72
- like_edge = [edge self->:Like :->current_profile[0]];
67
+ current_profile = [root-->(`?Profile)];
68
+ like_edge = [edge self->:Like:->current_profile[0]];
73
69
  del like_edge[0] ;
74
70
  report self ;
75
71
  }
76
72
 
77
73
  can comment with comment_tweet entry {
78
- current_profile = [root-->( ` ? Profile ) ];
74
+ current_profile = [root-->(`?Profile)];
79
75
  comment_node = current_profile[0] +>: Post() :+> Comment(
80
76
  content=visitor.content
81
77
  );
@@ -86,26 +82,27 @@ node Tweet {
86
82
 
87
83
  def get_info() -> TweetInfo {
88
84
  return TweetInfo(
89
- username=[self<-:Post :<-][0].username,
85
+ username=[self<-:Post:<-][0].username,
90
86
  id=jid(self),
91
87
  content=self.content,
92
88
  embedding=self.embedding,
93
- likes=[i.username for i in [self->:Like :->]],
89
+ likes=[i.username for i in [self->:Like:->]],
94
90
  comments=[
95
-
96
- {"username" : [i<--( ` ? Profile ) ][0].username , "id" : jid(i) , "content" : i.content }
97
- for i in [self-->( ` ? Comment ) ]
91
+ {
92
+ "username": [i<--(`?Profile)][0].username,
93
+ "id": jid(i),
94
+ "content": i.content
95
+ } for i in [self-->(`?Comment)]
98
96
  ]
99
97
  );
100
98
  }
101
99
 
102
100
  can get with load_feed entry {
103
101
  tweet_info = self.get_info();
104
- visitor.results.append({"Tweet_Info" : tweet_info });
102
+ visitor.results.append({"Tweet_Info": tweet_info});
105
103
  }
106
104
  }
107
105
 
108
-
109
106
  node Comment {
110
107
  has content: str;
111
108
 
@@ -120,19 +117,15 @@ node Comment {
120
117
  }
121
118
  }
122
119
 
123
-
124
120
  edge Follow {}
125
121
 
126
-
127
122
  edge Like {}
128
123
 
129
-
130
124
  edge Post {}
131
125
 
132
-
133
126
  walker visit_profile {
134
127
  can visit_profile with `root entry {
135
- visit [-->( ` ? Profile ) ] else {
128
+ visit [-->(`?Profile)] else {
136
129
  new_profile = here ++> Profile();
137
130
  grant(new_profile[0], level=ConnectPerm);
138
131
  visit new_profile;
@@ -140,21 +133,18 @@ walker visit_profile {
140
133
  }
141
134
  }
142
135
 
143
-
144
136
  walker update_profile(visit_profile) {
145
137
  has new_username: str;
146
138
  }
147
139
 
148
-
149
140
  walker get_profile(visit_profile) {}
150
141
 
151
-
152
142
  walker load_user_profiles {
153
143
  can load_profiles with `root entry {
154
144
  self.profiles: list = [];
155
145
  for each_root in allroots() {
156
- profile = [each_root-->( ` ? Profile ) ][0];
157
- self.profiles.append({"name" : profile.username , "id" : jid(profile) });
146
+ profile = [each_root-->(`?Profile)][0];
147
+ self.profiles.append({"name": profile.username, "id": jid(profile)});
158
148
  }
159
149
  }
160
150
 
@@ -163,13 +153,10 @@ walker load_user_profiles {
163
153
  }
164
154
  }
165
155
 
166
-
167
156
  walker follow_request {}
168
157
 
169
-
170
158
  walker un_follow_request {}
171
159
 
172
-
173
160
  walker create_tweet(visit_profile) {
174
161
  has content: str;
175
162
 
@@ -180,42 +167,34 @@ walker create_tweet(visit_profile) {
180
167
  }
181
168
  }
182
169
 
183
-
184
170
  walker update_tweet {
185
171
  has updated_content: str;
186
172
  }
187
173
 
188
-
189
174
  walker remove_tweet {}
190
175
 
191
-
192
176
  walker like_tweet {}
193
177
 
194
-
195
178
  walker remove_like {}
196
179
 
197
-
198
180
  walker comment_tweet {
199
181
  has content: str;
200
182
  }
201
183
 
202
-
203
184
  walker update_comment {
204
185
  has updated_content: str;
205
186
  }
206
187
 
207
-
208
188
  walker remove_comment {}
209
189
 
210
-
211
190
  walker load_feed(visit_profile) {
212
191
  has search_query: str = "";
213
192
  has results: list = [];
214
193
 
215
194
  can load with Profile entry {
216
- visit [-->( ` ? Tweet ) ];
217
- for user_node in [->:Follow :->( ` ? Profile ) ] {
218
- visit [user_node-->( ` ? Tweet ) ];
195
+ visit [-->(`?Tweet)];
196
+ for user_node in [->:Follow:->(`?Profile)] {
197
+ visit [user_node-->(`?Tweet)];
219
198
  }
220
199
  }
221
200
 
@@ -224,20 +203,16 @@ walker load_feed(visit_profile) {
224
203
  }
225
204
  }
226
205
 
227
-
228
206
  # Client-side UI Components (marked with 'cl' for browser execution)
229
207
  # ===================================================================
230
208
 
231
209
  # Reactive state management
232
- cl let [appState, setAppState] = createState({
233
- "tweets": [],
234
- "loading": False
235
- });
236
-
210
+ cl let [appState, setAppState] = createState(
211
+ {"tweets": [], "loading": False}
212
+ );
237
213
 
238
214
  # Manual routing functions removed - now using reactive createRouter
239
215
 
240
-
241
216
  # Shared data model for client/server
242
217
  cl obj ClientTweet {
243
218
  has username: str = "";
@@ -247,49 +222,56 @@ cl obj ClientTweet {
247
222
  has comments: list = [];
248
223
  }
249
224
 
250
-
251
225
  cl obj ClientProfile {
252
226
  has username: str = "";
253
227
  has id: str = "";
254
228
  }
255
229
 
256
-
257
230
  # UI Components - Render a single tweet card
258
231
  cl def TweetCard(tweet: ClientTweet) -> any {
259
232
  return <div
260
233
  class="tweet-card"
261
- style={
262
- {"border" : "1px solid #e1e8ed" , "padding" : "15px" , "margin" : "10px 0" , "borderRadius" : "8px" }}>
263
- <div
234
+ style={{
235
+ "border": "1px solid #e1e8ed",
236
+ "padding": "15px",
237
+ "margin": "10px 0",
238
+ "borderRadius": "8px"
239
+ }}
240
+ >
241
+ <div
264
242
  class="tweet-header"
265
- style={{"fontWeight" : "bold" , "marginBottom" : "80px" }}>
266
- @
267
- {tweet.username}
243
+ style={{"fontWeight": "bold", "marginBottom": "80px"}}
244
+ >
245
+ @{tweet.username}
268
246
  </div>
269
- <div class="tweet-content" style={{"marginBottom" : "12px" }}>
270
- {tweet.content}
247
+ <div
248
+ class="tweet-content"
249
+ style={{"marginBottom": "12px"}}
250
+ >
251
+ {tweet.content}
271
252
  </div>
272
- <div class="tweet-actions" style={{"display" : "flex" , "gap" : "15px" }}>
273
- <button
253
+ <div
254
+ class="tweet-actions"
255
+ style={{"display": "flex", "gap": "15px"}}
256
+ >
257
+ <button
274
258
  onclick={like_tweet_action(tweet.id)}
275
- style={{"padding" : "5px 10px" , "cursor" : "pointer" }}>
276
- Like (
277
- {tweet.likes.length}
278
- )
259
+ style={{"padding": "5px 10px", "cursor": "pointer"}}
260
+ >
261
+ Like ({tweet.likes.length})
279
262
  </button>
280
- <button style={{"padding" : "5px 10px" }}>
281
- Comment (
282
- {tweet.comments.length}
283
- )
263
+ <button
264
+ style={{"padding": "5px 10px"}}
265
+ >
266
+ Comment ({tweet.comments.length})
284
267
  </button>
285
268
  </div>
286
269
  </div>;
287
270
  }
288
271
 
289
-
290
272
  # Handle liking a tweet - calls server walker directly
291
273
  # The compiler automatically transforms this to __jacCallFunction at compile time!
292
- cl async def like_tweet_action(
274
+ cl async def like_tweet_action(
293
275
  tweet_id: str
294
276
  ) -> any {
295
277
  try {
@@ -302,27 +284,28 @@ cl def TweetCard(tweet: ClientTweet) -> any {
302
284
  }
303
285
  }
304
286
 
305
-
306
287
  # Render the main feed view
307
288
  cl def FeedView(tweets: list) -> any {
308
289
  return <div
309
290
  class="feed-container"
310
- style={
311
- {"maxWidth" : "600px" , "margin" : "0 auto" , "fontFamily" : "sans-serif" }}>
312
- <div
291
+ style={{"maxWidth": "600px", "margin": "0 auto", "fontFamily": "sans-serif"}}
292
+ >
293
+ <div
313
294
  class="feed-header"
314
- style={{"padding" : "20px" , "borderBottom" : "1px solid #e1e8ed" }}>
315
- <h1 style={{"margin" : "0" }}>
316
- LittleX Feed
295
+ style={{"padding": "20px", "borderBottom": "1px solid #e1e8ed"}}
296
+ >
297
+ <h1
298
+ style={{"margin": "0"}}
299
+ >
300
+ LittleX Feed
317
301
  </h1>
318
302
  </div>
319
- <div class="feed-content">
320
- {[TweetCard(tweet) for tweet in tweets]}
303
+ <div class="feed-content">
304
+ {[TweetCard(tweet) for tweet in tweets]}
321
305
  </div>
322
306
  </div>;
323
307
  }
324
308
 
325
-
326
309
  # Render login form
327
310
  cl def LoginForm() -> any {
328
311
  suggestions = ['good luck', 'have fun', 'enjoy the ride'];
@@ -330,58 +313,100 @@ cl def LoginForm() -> any {
330
313
  result = "Good luck with your journey!";
331
314
  return <Card
332
315
  title="Login to LittleX"
333
- style={
334
- {"maxWidth" : "400px" , "margin" : "50px auto" }}>
335
- <Card.Meta title={randomSuggestion} description={result} />
336
- <form onSubmit={handle_login}>
337
- <div style={{"marginBottom" : "15px" }}>
338
- <label style={{"display" : "block" , "marginBottom" : "5px" }}>
339
- Username:
316
+ style={{"maxWidth": "400px", "margin": "50px auto"}}
317
+ >
318
+ <Card.Meta
319
+ title={randomSuggestion}
320
+ description={result}
321
+ />
322
+ <form
323
+ onSubmit={handle_login}
324
+ >
325
+ <div
326
+ style={{"marginBottom": "15px"}}
327
+ >
328
+ <label
329
+ style={{"display": "block", "marginBottom": "5px"}}
330
+ >
331
+ Username:
340
332
  </label>
341
- <input
342
- type="text"
343
- id="username"
344
- style={
345
- {"width" : "100%" , "padding" : "8px" , "boxSizing" : "border-box" }}/>
333
+ <input
334
+ type="text"
335
+ id="username"
336
+ style={{
337
+ "width": "100%",
338
+ "padding": "8px",
339
+ "boxSizing": "border-box"
340
+ }}
341
+ />
346
342
  </div>
347
- <div style={{"marginBottom" : "15px" }}>
348
- <label style={{"display" : "block" , "marginBottom" : "5px" }}>
349
- Password:
343
+ <div
344
+ style={{"marginBottom": "15px"}}
345
+ >
346
+ <label
347
+ style={{"display": "block", "marginBottom": "5px"}}
348
+ >
349
+ Password:
350
350
  </label>
351
- <input
352
- type="password"
353
- id="password"
354
- style={
355
- {"width" : "100%" , "padding" : "8px" , "boxSizing" : "border-box" }}/>
351
+ <input
352
+ type="password"
353
+ id="password"
354
+ style={{
355
+ "width": "100%",
356
+ "padding": "8px",
357
+ "boxSizing": "border-box"
358
+ }}
359
+ />
356
360
  </div>
357
- <Button
361
+ <Button
358
362
  htmlType="submit"
359
- style={{"width" : "100%" , "padding" : "10px" , "backgroundColor" : "#1da1f2" , "color" : "white" , "border" : "none" , "borderRadius" : "4px" , "cursor" : "pointer" }}
360
- >
361
- Login
363
+ style={{
364
+ "width": "100%",
365
+ "padding": "10px",
366
+ "backgroundColor": "#1da1f2",
367
+ "color": "white",
368
+ "border": "none",
369
+ "borderRadius": "4px",
370
+ "cursor": "pointer"
371
+ }}
372
+ >
373
+ Login
374
+ </Button>
375
+ <Button
376
+ color="default"
377
+ variant="dashed"
378
+ >
379
+ Dashed
380
+ </Button>
381
+ <Button
382
+ color="default"
383
+ variant="filled"
384
+ >
385
+ Filled
386
+ </Button>
387
+ <Button
388
+ color="default"
389
+ variant="text"
390
+ >
391
+ Text
392
+ </Button>
393
+ <Button
394
+ color="default"
395
+ variant="link"
396
+ >
397
+ Link
362
398
  </Button>
363
- <Button color="default" variant="dashed">
364
- Dashed
365
- </Button>
366
- <Button color="default" variant="filled">
367
- Filled
368
- </Button>
369
- <Button color="default" variant="text">
370
- Text
371
- </Button>
372
- <Button color="default" variant="link">
373
- Link
374
- </Button>
375
399
  </form>
376
- <div style={{"marginTop" : "15px" , "textAlign" : "center" }}>
377
- <Link href="/signup">
378
- Don't have an account? Sign up
379
- </Link>
400
+ <div
401
+ style={{"marginTop": "15px", "textAlign": "center"}}
402
+ >
403
+ <Link href="/signup">
404
+ Don't have an account? Sign up
405
+ </Link>
380
406
  </div>
381
407
  </Card>;
382
408
  }
383
409
 
384
-
385
410
  # Handle login form submission
386
411
  cl async def handle_login(event: any) -> None {
387
412
  event.preventDefault();
@@ -395,69 +420,112 @@ cl async def handle_login(event: any) -> None {
395
420
  }
396
421
  }
397
422
 
398
-
399
423
  # Render signup form
400
424
  cl def SignupForm() -> any {
401
425
  return <div
402
426
  class="signup-container"
403
- style={
404
- {"maxWidth" : "400px" , "margin" : "50px auto" , "padding" : "20px" , "border" : "1px solid #e1e8ed" , "borderRadius" : "8px" , "fontFamily" : "sans-serif" }}>
405
- <Typography.Title level={2} style={{"marginTop" : "0" }}>
406
- Sign Up for LittleX
427
+ style={{
428
+ "maxWidth": "400px",
429
+ "margin": "50px auto",
430
+ "padding": "20px",
431
+ "border": "1px solid #e1e8ed",
432
+ "borderRadius": "8px",
433
+ "fontFamily": "sans-serif"
434
+ }}
435
+ >
436
+ <Typography.Title
437
+ level={2}
438
+ style={{"marginTop": "0"}}
439
+ >
440
+ Sign Up for LittleX
407
441
  </Typography.Title>
408
- <form onSubmit={handle_signup}>
409
- <div style={{"marginBottom" : "15px" }}>
410
- <label style={{"display" : "block" , "marginBottom" : "5px" }}>
411
- Username:
442
+ <form
443
+ onSubmit={handle_signup}
444
+ >
445
+ <div
446
+ style={{"marginBottom": "15px"}}
447
+ >
448
+ <label
449
+ style={{"display": "block", "marginBottom": "5px"}}
450
+ >
451
+ Username:
412
452
  </label>
413
- <input
414
- type="text"
415
- id="signup-username"
416
- required
417
- style={
418
- {"width" : "100%" , "padding" : "8px" , "boxSizing" : "border-box" }}/>
453
+ <input
454
+ type="text"
455
+ id="signup-username"
456
+ required
457
+ style={{
458
+ "width": "100%",
459
+ "padding": "8px",
460
+ "boxSizing": "border-box"
461
+ }}
462
+ />
419
463
  </div>
420
- <div style={{"marginBottom" : "15px" }}>
421
- <label style={{"display" : "block" , "marginBottom" : "5px" }}>
422
- Password:
464
+ <div
465
+ style={{"marginBottom": "15px"}}
466
+ >
467
+ <label
468
+ style={{"display": "block", "marginBottom": "5px"}}
469
+ >
470
+ Password:
423
471
  </label>
424
- <input
425
- type="password"
426
- id="signup-password"
427
- required
428
- style={
429
- {"width" : "100%" , "padding" : "8px" , "boxSizing" : "border-box" }}/>
472
+ <input
473
+ type="password"
474
+ id="signup-password"
475
+ required
476
+ style={{
477
+ "width": "100%",
478
+ "padding": "8px",
479
+ "boxSizing": "border-box"
480
+ }}
481
+ />
430
482
  </div>
431
- <div style={{"marginBottom" : "15px" }}>
432
- <label style={{"display" : "block" , "marginBottom" : "5px" }}>
433
- Confirm Password:
483
+ <div
484
+ style={{"marginBottom": "15px"}}
485
+ >
486
+ <label
487
+ style={{"display": "block", "marginBottom": "5px"}}
488
+ >
489
+ Confirm Password:
434
490
  </label>
435
- <input
436
- type="password"
437
- id="signup-password-confirm"
438
- required
439
- style={
440
- {"width" : "100%" , "padding" : "8px" , "boxSizing" : "border-box" }}/>
491
+ <input
492
+ type="password"
493
+ id="signup-password-confirm"
494
+ required
495
+ style={{
496
+ "width": "100%",
497
+ "padding": "8px",
498
+ "boxSizing": "border-box"
499
+ }}
500
+ />
441
501
  </div>
442
- <button
502
+ <button
443
503
  type="submit"
444
- style={
445
- {"width" : "100%" , "padding" : "10px" , "backgroundColor" : "#1da1f2" , "color" : "white" , "border" : "none" , "borderRadius" : "4px" , "cursor" : "pointer" }}>
446
- Sign Up
504
+ style={{
505
+ "width": "100%",
506
+ "padding": "10px",
507
+ "backgroundColor": "#1da1f2",
508
+ "color": "white",
509
+ "border": "none",
510
+ "borderRadius": "4px",
511
+ "cursor": "pointer"
512
+ }}
513
+ >
514
+ Sign Up
447
515
  </button>
448
516
  </form>
449
- <div style={{"marginTop" : "15px" , "textAlign" : "center" }}>
450
- <Link href="/login">
451
- Already have an account? Login
452
- </Link>
517
+ <div
518
+ style={{"marginTop": "15px", "textAlign": "center"}}
519
+ >
520
+ <Link href="/login">
521
+ Already have an account? Login
522
+ </Link>
453
523
  </div>
454
524
  </div>;
455
525
  }
456
526
 
457
-
458
527
  # Navigation helper functions removed - using Link component and navigate() directly
459
528
 
460
-
461
529
  # Handle signup form submission
462
530
  cl async def handle_signup(event: any) -> None {
463
531
  event.preventDefault();
@@ -465,7 +533,7 @@ cl async def handle_signup(event: any) -> None {
465
533
  password = document.getElementById("signup-password").value;
466
534
  password_confirm = document.getElementById("signup-password-confirm").value;
467
535
  # Client-side validation
468
- if password != password_confirm {
536
+ if password != password_confirm {
469
537
  alert("Passwords do not match!");
470
538
  return;
471
539
  }
@@ -487,35 +555,33 @@ cl async def handle_signup(event: any) -> None {
487
555
  }
488
556
  }
489
557
 
490
-
491
558
  # Handle logout
492
559
  cl def logout_action() -> None {
493
560
  jacLogout();
494
561
  navigate("/login");
495
562
  }
496
563
 
497
-
498
564
  # Main App component with declarative router
499
- cl def App() -> any {
565
+ cl def App() -> any {
500
566
  # Create routes array manually (workaround for JS compiler bug with named args)
501
567
  login_route = {
502
568
  "path": "/login",
503
- "component": lambda -> any { return LoginForm(); },
569
+ "component": lambda -> any{ return LoginForm(); } ,
504
570
  "guard": None
505
571
  };
506
572
  signup_route = {
507
573
  "path": "/signup",
508
- "component": lambda -> any { return SignupForm(); },
574
+ "component": lambda -> any{ return SignupForm(); } ,
509
575
  "guard": None
510
576
  };
511
577
  home_route = {
512
578
  "path": "/home",
513
- "component": lambda -> any { return HomeView(); },
579
+ "component": lambda -> any{ return HomeView(); } ,
514
580
  "guard": jacIsLoggedIn
515
581
  };
516
582
  profile_route = {
517
583
  "path": "/profile",
518
- "component": lambda -> any { return ProfileView(); },
584
+ "component": lambda -> any{ return ProfileView(); } ,
519
585
  "guard": jacIsLoggedIn
520
586
  };
521
587
 
@@ -528,88 +594,131 @@ cl def App() -> any {
528
594
  return <div class="app-container">
529
595
  {build_nav_bar(currentPath)}
530
596
  <Rotate>
531
- <span>
532
- 😂
533
- </span>
597
+ <span>
598
+ 😂
599
+ </span>
534
600
  </Rotate>
535
601
  {router.render()}
536
602
  </div>;
537
603
  }
538
604
 
539
-
540
605
  # Helper to build navigation bar
541
606
  cl def build_nav_bar(route: str) -> any {
542
607
  if not jacIsLoggedIn() or route == "/login" or route == "/signup" {
543
608
  return None;
544
609
  }
545
610
  return <nav
546
- style={
547
- {"backgroundColor" : "#1da1f2" , "padding" : "15px" , "marginBottom" : "20px" }}>
548
- <div
549
- style={
550
- {"maxWidth" : "600px" , "margin" : "0 auto" , "display" : "flex" , "gap" : "20px" , "alignItems" : "center" }}>
551
- <Link href="/home">
552
- <span style={{"color" : "white" , "textDecoration" : "none" , "fontWeight" : "bold"}}>
553
- Home
554
- </span>
555
- </Link>
556
- <Link href="/profile">
557
- <span style={{"color" : "white" , "textDecoration" : "none" , "fontWeight" : "bold"}}>
558
- Profile
559
- </span>
560
- </Link>
561
- <button
611
+ style={{
612
+ "backgroundColor": "#1da1f2",
613
+ "padding": "15px",
614
+ "marginBottom": "20px"
615
+ }}
616
+ >
617
+ <div
618
+ style={{
619
+ "maxWidth": "600px",
620
+ "margin": "0 auto",
621
+ "display": "flex",
622
+ "gap": "20px",
623
+ "alignItems": "center"
624
+ }}
625
+ >
626
+ <Link href="/home">
627
+ <span
628
+ style={{
629
+ "color": "white",
630
+ "textDecoration": "none",
631
+ "fontWeight": "bold"
632
+ }}
633
+ >
634
+ Home
635
+ </span>
636
+ </Link>
637
+ <Link href="/profile">
638
+ <span
639
+ style={{
640
+ "color": "white",
641
+ "textDecoration": "none",
642
+ "fontWeight": "bold"
643
+ }}
644
+ >
645
+ Profile
646
+ </span>
647
+ </Link>
648
+ <button
562
649
  onClick={logout_action}
563
- style={
564
- {"marginLeft" : "auto" , "padding" : "5px 15px" , "backgroundColor" : "white" , "color" : "#1da1f2" , "border" : "none" , "borderRadius" : "4px" , "cursor" : "pointer" , "fontWeight" : "bold" }}>
565
- Logout
650
+ style={{
651
+ "marginLeft": "auto",
652
+ "padding": "5px 15px",
653
+ "backgroundColor": "white",
654
+ "color": "#1da1f2",
655
+ "border": "none",
656
+ "borderRadius": "4px",
657
+ "cursor": "pointer",
658
+ "fontWeight": "bold"
659
+ }}
660
+ >
661
+ Logout
566
662
  </button>
567
663
  </div>
568
664
  </nav>;
569
665
  }
570
666
 
571
-
572
667
  # Home view - simplified for testing reactive routing
573
- cl def HomeView() -> any {
668
+ cl def HomeView() -> any {
574
669
  if not jacIsLoggedIn() {
575
670
  navigate("/login");
576
671
  return <div></div>;
577
672
  }
578
673
 
579
- return <div style={{"textAlign" : "center" , "padding" : "50px" , "fontFamily" : "sans-serif"}}>
580
- <h1>Home Feed</h1>
581
- <p>Welcome to LittleX! This is the home page.</p>
582
- <p>The reactive router is working!</p>
674
+ return <div
675
+ style={{"textAlign": "center", "padding": "50px", "fontFamily": "sans-serif"}}
676
+ >
677
+ <h1>
678
+ Home Feed
679
+ </h1>
680
+ <p>
681
+ Welcome to LittleX! This is the home page.
682
+ </p>
683
+ <p>
684
+ The reactive router is working!
685
+ </p>
583
686
  </div>;
584
687
  }
585
688
 
586
-
587
-
588
689
  # Profile view
589
- cl def ProfileView() -> any {
690
+ cl def ProfileView() -> any {
590
691
  if not jacIsLoggedIn() {
591
692
  navigate("/login");
592
693
  return <div></div>;
593
694
  }
594
695
  return <div
595
696
  class="profile-container"
596
- style={
597
- {"maxWidth" : "600px" , "margin" : "20px auto" , "padding" : "20px" , "fontFamily" : "sans-serif" }}>
598
- <h1>
599
- Profile
697
+ style={{
698
+ "maxWidth": "600px",
699
+ "margin": "20px auto",
700
+ "padding": "20px",
701
+ "fontFamily": "sans-serif"
702
+ }}
703
+ >
704
+ <h1>
705
+ Profile
600
706
  </h1>
601
- <div
602
- style={
603
- {"padding" : "15px" , "border" : "1px solid #e1e8ed" , "borderRadius" : "8px" }}>
604
- <p>
605
- Profile information will be displayed here.
707
+ <div
708
+ style={{
709
+ "padding": "15px",
710
+ "border": "1px solid #e1e8ed",
711
+ "borderRadius": "8px"
712
+ }}
713
+ >
714
+ <p>
715
+ Profile information will be displayed here.
606
716
  </p>
607
717
  </div>
608
718
  </div>;
609
719
  }
610
720
 
611
-
612
721
  # Main SPA entry point - simplified with reactive routing
613
- cl def jac_app() -> any {
722
+ cl def jac_app() -> any {
614
723
  return App();
615
724
  }