jac-client 0.2.0__py3-none-any.whl → 0.2.2__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/docs/README.md +50 -20
- jac_client/docs/advanced-state.md +13 -14
- jac_client/docs/asset-serving/intro.md +209 -0
- jac_client/docs/assets/pipe_line-v2.svg +32 -0
- jac_client/docs/file-system/app.jac.md +121 -0
- jac_client/docs/file-system/backend-frontend.md +217 -0
- jac_client/docs/file-system/intro.md +72 -0
- jac_client/docs/file-system/nested-imports.md +348 -0
- jac_client/docs/guide-example/intro.md +11 -13
- jac_client/docs/guide-example/step-01-setup.md +30 -20
- jac_client/docs/guide-example/step-02-components.md +24 -24
- jac_client/docs/guide-example/step-03-styling.md +24 -24
- jac_client/docs/guide-example/step-04-todo-ui.md +17 -17
- jac_client/docs/guide-example/step-05-local-state.md +23 -23
- jac_client/docs/guide-example/step-06-events.md +23 -24
- jac_client/docs/guide-example/step-07-effects.md +27 -28
- jac_client/docs/guide-example/step-08-walkers.md +23 -23
- jac_client/docs/guide-example/step-09-authentication.md +18 -18
- jac_client/docs/guide-example/step-10-routing.md +20 -21
- jac_client/docs/guide-example/step-11-final.md +34 -35
- jac_client/docs/imports.md +4 -5
- jac_client/docs/lifecycle-hooks.md +12 -13
- jac_client/docs/routing.md +21 -22
- jac_client/docs/styling/intro.md +249 -0
- jac_client/docs/styling/js-styling.md +367 -0
- jac_client/docs/styling/material-ui.md +341 -0
- jac_client/docs/styling/pure-css.md +299 -0
- jac_client/docs/styling/sass.md +403 -0
- jac_client/docs/styling/styled-components.md +395 -0
- jac_client/docs/styling/tailwind.md +298 -0
- jac_client/examples/all-in-one/.babelrc +9 -0
- jac_client/examples/all-in-one/README.md +16 -0
- jac_client/examples/all-in-one/app.jac +426 -0
- jac_client/examples/all-in-one/assets/burger.png +0 -0
- jac_client/examples/all-in-one/button.jac +7 -0
- jac_client/examples/all-in-one/components/button.jac +7 -0
- jac_client/examples/all-in-one/package.json +29 -0
- jac_client/examples/all-in-one/styles.css +26 -0
- jac_client/examples/all-in-one/vite.config.js +28 -0
- jac_client/examples/asset-serving/css-with-image/.babelrc +9 -0
- jac_client/examples/asset-serving/css-with-image/README.md +91 -0
- jac_client/examples/asset-serving/css-with-image/app.jac +88 -0
- jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
- jac_client/examples/asset-serving/css-with-image/package.json +28 -0
- jac_client/examples/asset-serving/css-with-image/styles.css +26 -0
- jac_client/examples/asset-serving/css-with-image/vite.config.js +28 -0
- jac_client/examples/asset-serving/image-asset/.babelrc +9 -0
- jac_client/examples/asset-serving/image-asset/README.md +119 -0
- jac_client/examples/asset-serving/image-asset/app.jac +55 -0
- jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
- jac_client/examples/asset-serving/image-asset/package.json +28 -0
- jac_client/examples/asset-serving/image-asset/styles.css +26 -0
- jac_client/examples/asset-serving/image-asset/vite.config.js +28 -0
- jac_client/examples/asset-serving/import-alias/.babelrc +9 -0
- jac_client/examples/asset-serving/import-alias/README.md +83 -0
- jac_client/examples/asset-serving/import-alias/app.jac +111 -0
- jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
- jac_client/examples/asset-serving/import-alias/package.json +28 -0
- jac_client/examples/asset-serving/import-alias/vite.config.js +28 -0
- jac_client/examples/basic/app.jac +14 -9
- jac_client/examples/basic/package.json +1 -1
- jac_client/examples/basic/vite.config.js +0 -1
- jac_client/examples/basic-auth/package.json +1 -1
- jac_client/examples/basic-auth/vite.config.js +0 -1
- jac_client/examples/basic-auth-with-router/package.json +1 -1
- jac_client/examples/basic-auth-with-router/vite.config.js +0 -1
- jac_client/examples/basic-full-stack/package.json +1 -1
- jac_client/examples/basic-full-stack/vite.config.js +0 -1
- jac_client/examples/css-styling/js-styling/.babelrc +9 -0
- jac_client/examples/css-styling/js-styling/README.md +183 -0
- jac_client/examples/css-styling/js-styling/app.jac +84 -0
- jac_client/examples/css-styling/js-styling/package.json +28 -0
- jac_client/examples/css-styling/js-styling/styles.js +100 -0
- jac_client/examples/css-styling/js-styling/vite.config.js +27 -0
- jac_client/examples/css-styling/material-ui/.babelrc +9 -0
- jac_client/examples/css-styling/material-ui/README.md +16 -0
- jac_client/examples/css-styling/material-ui/app.jac +122 -0
- jac_client/examples/css-styling/material-ui/package.json +32 -0
- jac_client/examples/css-styling/material-ui/vite.config.js +27 -0
- jac_client/examples/css-styling/pure-css/.babelrc +9 -0
- jac_client/examples/css-styling/pure-css/README.md +16 -0
- jac_client/examples/css-styling/pure-css/app.jac +64 -0
- jac_client/examples/css-styling/pure-css/package.json +28 -0
- jac_client/examples/css-styling/pure-css/styles.css +111 -0
- jac_client/examples/css-styling/pure-css/vite.config.js +27 -0
- jac_client/examples/css-styling/sass-example/.babelrc +9 -0
- jac_client/examples/css-styling/sass-example/README.md +16 -0
- jac_client/examples/css-styling/sass-example/app.jac +64 -0
- jac_client/examples/css-styling/sass-example/package.json +29 -0
- jac_client/examples/css-styling/sass-example/styles.scss +153 -0
- jac_client/examples/css-styling/sass-example/vite.config.js +27 -0
- jac_client/examples/css-styling/styled-components/.babelrc +9 -0
- jac_client/examples/css-styling/styled-components/README.md +16 -0
- jac_client/examples/css-styling/styled-components/app.jac +71 -0
- jac_client/examples/css-styling/styled-components/package.json +29 -0
- jac_client/examples/css-styling/styled-components/styled.js +90 -0
- jac_client/examples/css-styling/styled-components/vite.config.js +27 -0
- jac_client/examples/css-styling/tailwind-example/.babelrc +9 -0
- jac_client/examples/css-styling/tailwind-example/README.md +16 -0
- jac_client/examples/css-styling/tailwind-example/app.jac +63 -0
- jac_client/examples/css-styling/tailwind-example/global.css +1 -0
- jac_client/examples/css-styling/tailwind-example/package.json +30 -0
- jac_client/examples/css-styling/tailwind-example/vite.config.js +29 -0
- jac_client/examples/full-stack-with-auth/app.jac +20 -33
- jac_client/examples/full-stack-with-auth/package.json +1 -1
- jac_client/examples/full-stack-with-auth/vite.config.js +0 -1
- jac_client/examples/little-x/app.jac +327 -218
- jac_client/examples/little-x/submit-button.jac +1 -1
- jac_client/examples/nested-folders/nested-advance/.babelrc +9 -0
- jac_client/examples/nested-folders/nested-advance/ButtonRoot.jac +11 -0
- jac_client/examples/nested-folders/nested-advance/README.md +77 -0
- jac_client/examples/nested-folders/nested-advance/app.jac +35 -0
- jac_client/examples/nested-folders/nested-advance/level1/ButtonSecondL.jac +19 -0
- jac_client/examples/nested-folders/nested-advance/level1/Card.jac +43 -0
- jac_client/examples/nested-folders/nested-advance/level1/level2/ButtonThirdL.jac +25 -0
- jac_client/examples/nested-folders/nested-advance/package.json +29 -0
- jac_client/examples/nested-folders/nested-advance/vite.config.js +28 -0
- jac_client/examples/nested-folders/nested-basic/.babelrc +9 -0
- jac_client/examples/nested-folders/nested-basic/README.md +183 -0
- jac_client/examples/nested-folders/nested-basic/app.jac +13 -0
- jac_client/examples/nested-folders/nested-basic/app.js +7 -0
- jac_client/examples/nested-folders/nested-basic/button.jac +7 -0
- jac_client/examples/nested-folders/nested-basic/components/button.jac +7 -0
- jac_client/examples/nested-folders/nested-basic/package.json +28 -0
- jac_client/examples/nested-folders/nested-basic/vite.config.js +27 -0
- jac_client/examples/with-router/app.jac +1 -1
- jac_client/examples/with-router/package.json +1 -1
- jac_client/examples/with-router/vite.config.js +0 -1
- jac_client/plugin/cli.py +7 -2
- jac_client/plugin/client.py +68 -5
- jac_client/plugin/client_runtime.jac +1 -1
- jac_client/plugin/vite_client_bundle.py +162 -14
- jac_client/tests/__init__.py +0 -1
- jac_client/tests/fixtures/basic-app/app.jac +7 -2
- jac_client/tests/fixtures/cl_file/app.cl.jac +48 -0
- jac_client/tests/fixtures/cl_file/app.jac +15 -0
- jac_client/tests/fixtures/client_app_with_antd/app.jac +14 -8
- jac_client/tests/fixtures/js_import/app.jac +19 -15
- jac_client/tests/fixtures/js_import/utils.js +0 -1
- jac_client/tests/fixtures/package.json +1 -1
- jac_client/tests/fixtures/relative_import/app.jac +4 -6
- jac_client/tests/fixtures/relative_import/button.jac +7 -6
- jac_client/tests/fixtures/spawn_test/app.jac +1 -5
- jac_client/tests/fixtures/test_fragments_spread/app.jac +24 -10
- jac_client/tests/test_asset_examples.py +322 -0
- jac_client/tests/test_cl.py +480 -426
- jac_client/tests/test_create_jac_app.py +125 -133
- jac_client/tests/test_it.py +329 -0
- jac_client/tests/test_nested_file.py +374 -0
- {jac_client-0.2.0.dist-info → jac_client-0.2.2.dist-info}/METADATA +2 -2
- jac_client-0.2.2.dist-info/RECORD +171 -0
- jac_client-0.2.0.dist-info/RECORD +0 -72
- {jac_client-0.2.0.dist-info → jac_client-0.2.2.dist-info}/WHEEL +0 -0
- {jac_client-0.2.0.dist-info → jac_client-0.2.2.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"
|
|
18
|
-
for i in [self-->( ` ? Profile ) ]
|
|
17
|
+
{"id": jid(i), "username": i.username} for i in [self-->(`?Profile)]
|
|
19
18
|
];
|
|
20
|
-
report {"user"
|
|
19
|
+
report {"user": self, "followers": follwers} ;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
can follow with follow_request entry {
|
|
24
|
-
current_profile = [root-->(
|
|
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
|
-
|
|
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-->(
|
|
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-->(
|
|
72
|
-
like_edge = [edge self->:Like
|
|
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-->(
|
|
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
|
|
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
|
-
|
|
97
|
-
|
|
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"
|
|
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 [-->(
|
|
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-->(
|
|
157
|
-
self.profiles.append({"name"
|
|
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 [-->(
|
|
217
|
-
for user_node in [->:Follow
|
|
218
|
-
visit [user_node-->(
|
|
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
|
-
|
|
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
|
-
|
|
263
|
-
|
|
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"
|
|
266
|
-
|
|
267
|
-
|
|
243
|
+
style={{"fontWeight": "bold", "marginBottom": "80px"}}
|
|
244
|
+
>
|
|
245
|
+
@{tweet.username}
|
|
268
246
|
</div>
|
|
269
|
-
|
|
270
|
-
|
|
247
|
+
<div
|
|
248
|
+
class="tweet-content"
|
|
249
|
+
style={{"marginBottom": "12px"}}
|
|
250
|
+
>
|
|
251
|
+
{tweet.content}
|
|
271
252
|
</div>
|
|
272
|
-
|
|
273
|
-
|
|
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"
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
)
|
|
259
|
+
style={{"padding": "5px 10px", "cursor": "pointer"}}
|
|
260
|
+
>
|
|
261
|
+
Like ({tweet.likes.length})
|
|
279
262
|
</button>
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
-
|
|
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
|
-
|
|
312
|
-
|
|
291
|
+
style={{"maxWidth": "600px", "margin": "0 auto", "fontFamily": "sans-serif"}}
|
|
292
|
+
>
|
|
293
|
+
<div
|
|
313
294
|
class="feed-header"
|
|
314
|
-
style={{"padding"
|
|
315
|
-
|
|
316
|
-
|
|
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
|
-
|
|
320
|
-
|
|
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
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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
|
-
|
|
348
|
-
|
|
349
|
-
|
|
343
|
+
<div
|
|
344
|
+
style={{"marginBottom": "15px"}}
|
|
345
|
+
>
|
|
346
|
+
<label
|
|
347
|
+
style={{"display": "block", "marginBottom": "5px"}}
|
|
348
|
+
>
|
|
349
|
+
Password:
|
|
350
350
|
</label>
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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
|
-
|
|
361
|
+
<Button
|
|
358
362
|
htmlType="submit"
|
|
359
|
-
style={{
|
|
360
|
-
|
|
361
|
-
|
|
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
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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
|
-
|
|
421
|
-
|
|
422
|
-
|
|
464
|
+
<div
|
|
465
|
+
style={{"marginBottom": "15px"}}
|
|
466
|
+
>
|
|
467
|
+
<label
|
|
468
|
+
style={{"display": "block", "marginBottom": "5px"}}
|
|
469
|
+
>
|
|
470
|
+
Password:
|
|
423
471
|
</label>
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|
-
|
|
432
|
-
|
|
433
|
-
|
|
483
|
+
<div
|
|
484
|
+
style={{"marginBottom": "15px"}}
|
|
485
|
+
>
|
|
486
|
+
<label
|
|
487
|
+
style={{"display": "block", "marginBottom": "5px"}}
|
|
488
|
+
>
|
|
489
|
+
Confirm Password:
|
|
434
490
|
</label>
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
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
|
-
|
|
502
|
+
<button
|
|
443
503
|
type="submit"
|
|
444
|
-
style={
|
|
445
|
-
|
|
446
|
-
|
|
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
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
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
|
-
|
|
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()
|
|
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
|
|
569
|
+
"component": lambda -> any{ return LoginForm(); } ,
|
|
504
570
|
"guard": None
|
|
505
571
|
};
|
|
506
572
|
signup_route = {
|
|
507
573
|
"path": "/signup",
|
|
508
|
-
"component": lambda
|
|
574
|
+
"component": lambda -> any{ return SignupForm(); } ,
|
|
509
575
|
"guard": None
|
|
510
576
|
};
|
|
511
577
|
home_route = {
|
|
512
578
|
"path": "/home",
|
|
513
|
-
"component": lambda
|
|
579
|
+
"component": lambda -> any{ return HomeView(); } ,
|
|
514
580
|
"guard": jacIsLoggedIn
|
|
515
581
|
};
|
|
516
582
|
profile_route = {
|
|
517
583
|
"path": "/profile",
|
|
518
|
-
"component": lambda
|
|
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
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
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
|
-
|
|
565
|
-
|
|
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()
|
|
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
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
<
|
|
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()
|
|
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
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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
|
-
|
|
602
|
-
style={
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
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()
|
|
722
|
+
cl def jac_app() -> any {
|
|
614
723
|
return App();
|
|
615
724
|
}
|