jac-client 0.2.6__py3-none-any.whl → 0.2.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jac_client/examples/all-in-one/{src/button.jac → button.jac} +4 -3
- jac_client/examples/all-in-one/components/CategoryFilter.jac +47 -0
- jac_client/examples/all-in-one/components/Header.jac +17 -0
- jac_client/examples/all-in-one/components/ProfitOverview.jac +64 -0
- jac_client/examples/all-in-one/components/Summary.jac +76 -0
- jac_client/examples/all-in-one/components/TransactionForm.jac +188 -0
- jac_client/examples/all-in-one/components/TransactionItem.jac +62 -0
- jac_client/examples/all-in-one/components/TransactionList.jac +44 -0
- jac_client/examples/all-in-one/components/button.jac +8 -0
- jac_client/examples/all-in-one/components/navigation.jac +126 -0
- jac_client/examples/all-in-one/constants/categories.jac +36 -0
- jac_client/examples/all-in-one/constants/clients.jac +12 -0
- jac_client/examples/all-in-one/context/BudgetContext.jac +31 -0
- jac_client/examples/all-in-one/hooks/useBudget.jac +122 -0
- jac_client/examples/all-in-one/hooks/useLocalStorage.jac +37 -0
- jac_client/examples/all-in-one/main.jac +542 -0
- jac_client/examples/all-in-one/pages/BudgetPlanner.jac +140 -0
- jac_client/examples/all-in-one/pages/FeaturesTest.jac +157 -0
- jac_client/examples/all-in-one/pages/LandingPage.jac +124 -0
- jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +65 -0
- jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +675 -0
- jac_client/examples/all-in-one/pages/loginPage.jac +127 -0
- jac_client/examples/all-in-one/pages/nestedDemo.jac +54 -0
- jac_client/examples/all-in-one/pages/notFound.jac +18 -0
- jac_client/examples/all-in-one/pages/signupPage.jac +127 -0
- jac_client/examples/all-in-one/utils/formatters.jac +49 -0
- jac_client/examples/asset-serving/css-with-image/main.jac +92 -0
- jac_client/examples/asset-serving/image-asset/main.jac +56 -0
- jac_client/examples/asset-serving/import-alias/main.jac +109 -0
- jac_client/examples/basic/main.jac +23 -0
- jac_client/examples/basic-auth/main.jac +363 -0
- jac_client/examples/basic-auth-with-router/main.jac +451 -0
- jac_client/examples/basic-full-stack/main.jac +362 -0
- jac_client/examples/css-styling/js-styling/main.jac +63 -0
- jac_client/examples/css-styling/material-ui/main.jac +122 -0
- jac_client/examples/css-styling/pure-css/main.jac +55 -0
- jac_client/examples/css-styling/sass-example/main.jac +55 -0
- jac_client/examples/css-styling/styled-components/main.jac +62 -0
- jac_client/examples/css-styling/tailwind-example/main.jac +74 -0
- jac_client/examples/full-stack-with-auth/main.jac +696 -0
- jac_client/examples/little-x/main.jac +681 -0
- jac_client/examples/little-x/src/submit-button.jac +15 -14
- jac_client/examples/nested-folders/nested-advance/main.jac +26 -0
- jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +4 -6
- jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +9 -13
- jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +29 -32
- jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +12 -18
- jac_client/examples/nested-folders/nested-basic/{src/app.jac → main.jac} +7 -5
- jac_client/examples/nested-folders/nested-basic/src/button.jac +4 -3
- jac_client/examples/nested-folders/nested-basic/src/components/button.jac +4 -3
- jac_client/examples/ts-support/main.jac +35 -0
- jac_client/examples/with-router/main.jac +286 -0
- jac_client/plugin/cli.jac +507 -470
- jac_client/plugin/client.jac +30 -12
- jac_client/plugin/client_runtime.cl.jac +25 -15
- jac_client/plugin/impl/client.impl.jac +126 -26
- jac_client/plugin/impl/client_runtime.impl.jac +182 -10
- jac_client/plugin/plugin_config.jac +216 -34
- jac_client/plugin/src/__init__.jac +0 -2
- jac_client/plugin/src/compiler.jac +2 -2
- jac_client/plugin/src/config_loader.jac +1 -0
- jac_client/plugin/src/desktop_config.jac +31 -0
- jac_client/plugin/src/impl/compiler.impl.jac +99 -30
- jac_client/plugin/src/impl/config_loader.impl.jac +8 -0
- jac_client/plugin/src/impl/desktop_config.impl.jac +191 -0
- jac_client/plugin/src/impl/jac_to_js.impl.jac +5 -1
- jac_client/plugin/src/impl/package_installer.impl.jac +20 -20
- jac_client/plugin/src/impl/vite_bundler.impl.jac +384 -144
- jac_client/plugin/src/package_installer.jac +1 -1
- jac_client/plugin/src/targets/desktop/sidecar/main.py +144 -0
- jac_client/plugin/src/targets/desktop_target.jac +37 -0
- jac_client/plugin/src/targets/impl/desktop_target.impl.jac +2347 -0
- jac_client/plugin/src/targets/impl/registry.impl.jac +64 -0
- jac_client/plugin/src/targets/impl/web_target.impl.jac +157 -0
- jac_client/plugin/src/targets/register.jac +21 -0
- jac_client/plugin/src/targets/registry.jac +87 -0
- jac_client/plugin/src/targets/web_target.jac +35 -0
- jac_client/plugin/src/vite_bundler.jac +15 -1
- jac_client/plugin/utils/__init__.jac +3 -0
- jac_client/plugin/utils/bun_installer.jac +16 -0
- jac_client/plugin/utils/impl/bun_installer.impl.jac +99 -0
- jac_client/templates/client.jacpack +72 -0
- jac_client/templates/fullstack.jacpack +61 -0
- jac_client/tests/conftest.py +110 -52
- jac_client/tests/fixtures/spawn_test/app.jac +64 -70
- jac_client/tests/fixtures/with-ts/app.jac +28 -28
- jac_client/tests/test_cli.py +280 -113
- jac_client/tests/test_e2e.py +232 -0
- jac_client/tests/test_helpers.py +58 -0
- jac_client/tests/test_it.py +325 -154
- jac_client/tests/test_it_desktop.py +891 -0
- {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/METADATA +20 -11
- jac_client-0.2.11.dist-info/RECORD +113 -0
- {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/WHEEL +1 -1
- jac_client/examples/all-in-one/src/app.jac +0 -841
- jac_client/examples/all-in-one/src/components/button.jac +0 -7
- jac_client/examples/asset-serving/css-with-image/src/app.jac +0 -88
- jac_client/examples/asset-serving/image-asset/src/app.jac +0 -55
- jac_client/examples/asset-serving/import-alias/src/app.jac +0 -111
- jac_client/examples/basic/src/app.jac +0 -21
- jac_client/examples/basic-auth/src/app.jac +0 -377
- jac_client/examples/basic-auth-with-router/src/app.jac +0 -464
- jac_client/examples/basic-full-stack/src/app.jac +0 -365
- jac_client/examples/css-styling/js-styling/src/app.jac +0 -84
- jac_client/examples/css-styling/material-ui/src/app.jac +0 -122
- jac_client/examples/css-styling/pure-css/src/app.jac +0 -64
- jac_client/examples/css-styling/sass-example/src/app.jac +0 -64
- jac_client/examples/css-styling/styled-components/src/app.jac +0 -71
- jac_client/examples/css-styling/tailwind-example/src/app.jac +0 -63
- jac_client/examples/full-stack-with-auth/src/app.jac +0 -722
- jac_client/examples/little-x/src/app.jac +0 -719
- jac_client/examples/nested-folders/nested-advance/src/app.jac +0 -35
- jac_client/examples/ts-support/src/app.jac +0 -35
- jac_client/examples/with-router/src/app.jac +0 -323
- jac_client/plugin/src/babel_processor.jac +0 -18
- jac_client/plugin/src/impl/babel_processor.impl.jac +0 -84
- jac_client-0.2.6.dist-info/RECORD +0 -74
- {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/entry_points.txt +0 -0
- {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
cl import from "@jac/runtime" { Link, useNavigate, jacLogin }
|
|
2
|
+
|
|
3
|
+
cl {
|
|
4
|
+
def:pub LoginPage -> any {
|
|
5
|
+
has username: str = "",
|
|
6
|
+
password: str = "",
|
|
7
|
+
error: str = "";
|
|
8
|
+
|
|
9
|
+
navigate = useNavigate();
|
|
10
|
+
|
|
11
|
+
async def handleLogin(e: any) -> None {
|
|
12
|
+
e.preventDefault();
|
|
13
|
+
error = "";
|
|
14
|
+
if not username or not password {
|
|
15
|
+
error = "Please fill in all fields";
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
success = await jacLogin(username, password);
|
|
19
|
+
if success {
|
|
20
|
+
navigate("/");
|
|
21
|
+
} else {
|
|
22
|
+
error = "Invalid credentials";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
def handleUsernameChange(e: any) -> None {
|
|
27
|
+
username = e.target.value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
def handlePasswordChange(e: any) -> None {
|
|
31
|
+
password = e.target.value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
errorDisplay = None;
|
|
35
|
+
if error {
|
|
36
|
+
errorDisplay = <div
|
|
37
|
+
style={{"color": "#dc2626", "fontSize": "14px", "marginBottom": "12px"}}
|
|
38
|
+
>
|
|
39
|
+
{error}
|
|
40
|
+
</div>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return
|
|
44
|
+
<div
|
|
45
|
+
style={{
|
|
46
|
+
"minHeight": "calc(100vh - 56px)",
|
|
47
|
+
"display": "flex",
|
|
48
|
+
"alignItems": "center",
|
|
49
|
+
"justifyContent": "center",
|
|
50
|
+
"background": "#f5f5f5"
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<div
|
|
54
|
+
style={{
|
|
55
|
+
"background": "#ffffff",
|
|
56
|
+
"padding": "32px",
|
|
57
|
+
"borderRadius": "8px",
|
|
58
|
+
"width": "300px",
|
|
59
|
+
"boxShadow": "0 2px 8px rgba(0,0,0,0.1)"
|
|
60
|
+
}}
|
|
61
|
+
>
|
|
62
|
+
<h2 style={{"marginBottom": "24px", "textAlign": "center"}}>
|
|
63
|
+
Login
|
|
64
|
+
</h2>
|
|
65
|
+
<form onSubmit={handleLogin}>
|
|
66
|
+
<input
|
|
67
|
+
type="text"
|
|
68
|
+
value={username}
|
|
69
|
+
onChange={handleUsernameChange}
|
|
70
|
+
placeholder="Username"
|
|
71
|
+
style={{
|
|
72
|
+
"width": "100%",
|
|
73
|
+
"padding": "10px",
|
|
74
|
+
"marginBottom": "12px",
|
|
75
|
+
"border": "1px solid #ddd",
|
|
76
|
+
"borderRadius": "4px",
|
|
77
|
+
"boxSizing": "border-box"
|
|
78
|
+
}}
|
|
79
|
+
/>
|
|
80
|
+
<input
|
|
81
|
+
type="password"
|
|
82
|
+
value={password}
|
|
83
|
+
onChange={handlePasswordChange}
|
|
84
|
+
placeholder="Password"
|
|
85
|
+
style={{
|
|
86
|
+
"width": "100%",
|
|
87
|
+
"padding": "10px",
|
|
88
|
+
"marginBottom": "12px",
|
|
89
|
+
"border": "1px solid #ddd",
|
|
90
|
+
"borderRadius": "4px",
|
|
91
|
+
"boxSizing": "border-box"
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
{errorDisplay}
|
|
95
|
+
<button
|
|
96
|
+
type="submit"
|
|
97
|
+
style={{
|
|
98
|
+
"width": "100%",
|
|
99
|
+
"padding": "10px",
|
|
100
|
+
"background": "#3b82f6",
|
|
101
|
+
"color": "#ffffff",
|
|
102
|
+
"border": "none",
|
|
103
|
+
"borderRadius": "4px",
|
|
104
|
+
"cursor": "pointer",
|
|
105
|
+
"fontWeight": "600"
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
Login
|
|
109
|
+
</button>
|
|
110
|
+
</form>
|
|
111
|
+
<p
|
|
112
|
+
style={{
|
|
113
|
+
"textAlign": "center",
|
|
114
|
+
"marginTop": "16px",
|
|
115
|
+
"fontSize": "14px"
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
Need an account?
|
|
119
|
+
{" "}
|
|
120
|
+
<Link to="/signup">
|
|
121
|
+
Sign up
|
|
122
|
+
</Link>
|
|
123
|
+
</p>
|
|
124
|
+
</div>
|
|
125
|
+
</div>;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Nested folder imports (same pattern as nested-basic/)
|
|
2
|
+
cl import from ..components.nestedDemo.CustomButton.tsx {
|
|
3
|
+
CustomButton
|
|
4
|
+
}
|
|
5
|
+
cl import from ..button { CustomButtonRoot }
|
|
6
|
+
cl import from "@jac/runtime" { Navigate, jacIsLoggedIn }
|
|
7
|
+
|
|
8
|
+
cl {
|
|
9
|
+
def:pub NestedImportsDemo -> any {
|
|
10
|
+
# Check if user is logged in, redirect if not
|
|
11
|
+
if not jacIsLoggedIn() {
|
|
12
|
+
return
|
|
13
|
+
<Navigate to="/login" />;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return
|
|
17
|
+
<div
|
|
18
|
+
style={{
|
|
19
|
+
"padding": "2rem",
|
|
20
|
+
"fontFamily": "system-ui, -apple-system, sans-serif"
|
|
21
|
+
}}
|
|
22
|
+
>
|
|
23
|
+
<h1>
|
|
24
|
+
📁 Nested Folder Imports
|
|
25
|
+
</h1>
|
|
26
|
+
<p>
|
|
27
|
+
This page mirrors the
|
|
28
|
+
{" "}
|
|
29
|
+
<code>
|
|
30
|
+
nested-folders/nested-basic
|
|
31
|
+
</code>
|
|
32
|
+
{" "}
|
|
33
|
+
example by importing components from both
|
|
34
|
+
{" "}
|
|
35
|
+
<code>
|
|
36
|
+
components.button
|
|
37
|
+
</code>
|
|
38
|
+
{" "}
|
|
39
|
+
and
|
|
40
|
+
{" "}
|
|
41
|
+
<code>
|
|
42
|
+
button
|
|
43
|
+
</code>
|
|
44
|
+
</p>
|
|
45
|
+
<p style={{"marginTop": "0.75rem"}}>
|
|
46
|
+
Both buttons below are rendered via relative imports:
|
|
47
|
+
</p>
|
|
48
|
+
<div style={{"display": "flex", "gap": "1rem", "marginTop": "1.5rem"}}>
|
|
49
|
+
<CustomButton />
|
|
50
|
+
<CustomButtonRoot />
|
|
51
|
+
</div>
|
|
52
|
+
</div>;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
cl import from "@jac/runtime" { Link }
|
|
2
|
+
cl import "..styles/notFoundPage/NotFoundstyle.css";
|
|
3
|
+
cl {
|
|
4
|
+
def:pub NotFound -> any {
|
|
5
|
+
return
|
|
6
|
+
<div className="not-found-container">
|
|
7
|
+
<h1>
|
|
8
|
+
🔍 404 - Page Not Found
|
|
9
|
+
</h1>
|
|
10
|
+
<p>
|
|
11
|
+
The page you are looking for does not exist.
|
|
12
|
+
</p>
|
|
13
|
+
<Link to="/">
|
|
14
|
+
← Back to Home
|
|
15
|
+
</Link>
|
|
16
|
+
</div>;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
cl import from "@jac/runtime" { Link, useNavigate, jacSignup }
|
|
2
|
+
|
|
3
|
+
cl {
|
|
4
|
+
def:pub SignupPage -> any {
|
|
5
|
+
has username: str = "",
|
|
6
|
+
password: str = "",
|
|
7
|
+
error: str = "";
|
|
8
|
+
|
|
9
|
+
navigate = useNavigate();
|
|
10
|
+
|
|
11
|
+
async def handleSignup(e: any) -> None {
|
|
12
|
+
e.preventDefault();
|
|
13
|
+
error = "";
|
|
14
|
+
if not username or not password {
|
|
15
|
+
error = "Please fill in all fields";
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
result = await jacSignup(username, password);
|
|
19
|
+
if result["success"] {
|
|
20
|
+
navigate("/");
|
|
21
|
+
} else {
|
|
22
|
+
error = result["error"] if result["error"] else "Signup failed";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
def handleUsernameChange(e: any) -> None {
|
|
27
|
+
username = e.target.value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
def handlePasswordChange(e: any) -> None {
|
|
31
|
+
password = e.target.value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
errorDisplay = None;
|
|
35
|
+
if error {
|
|
36
|
+
errorDisplay = <div
|
|
37
|
+
style={{"color": "#dc2626", "fontSize": "14px", "marginBottom": "12px"}}
|
|
38
|
+
>
|
|
39
|
+
{error}
|
|
40
|
+
</div>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return
|
|
44
|
+
<div
|
|
45
|
+
style={{
|
|
46
|
+
"minHeight": "calc(100vh - 56px)",
|
|
47
|
+
"display": "flex",
|
|
48
|
+
"alignItems": "center",
|
|
49
|
+
"justifyContent": "center",
|
|
50
|
+
"background": "#f5f5f5"
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<div
|
|
54
|
+
style={{
|
|
55
|
+
"background": "#ffffff",
|
|
56
|
+
"padding": "32px",
|
|
57
|
+
"borderRadius": "8px",
|
|
58
|
+
"width": "300px",
|
|
59
|
+
"boxShadow": "0 2px 8px rgba(0,0,0,0.1)"
|
|
60
|
+
}}
|
|
61
|
+
>
|
|
62
|
+
<h2 style={{"marginBottom": "24px", "textAlign": "center"}}>
|
|
63
|
+
Sign Up
|
|
64
|
+
</h2>
|
|
65
|
+
<form onSubmit={handleSignup}>
|
|
66
|
+
<input
|
|
67
|
+
type="text"
|
|
68
|
+
value={username}
|
|
69
|
+
onChange={handleUsernameChange}
|
|
70
|
+
placeholder="Username"
|
|
71
|
+
style={{
|
|
72
|
+
"width": "100%",
|
|
73
|
+
"padding": "10px",
|
|
74
|
+
"marginBottom": "12px",
|
|
75
|
+
"border": "1px solid #ddd",
|
|
76
|
+
"borderRadius": "4px",
|
|
77
|
+
"boxSizing": "border-box"
|
|
78
|
+
}}
|
|
79
|
+
/>
|
|
80
|
+
<input
|
|
81
|
+
type="password"
|
|
82
|
+
value={password}
|
|
83
|
+
onChange={handlePasswordChange}
|
|
84
|
+
placeholder="Password"
|
|
85
|
+
style={{
|
|
86
|
+
"width": "100%",
|
|
87
|
+
"padding": "10px",
|
|
88
|
+
"marginBottom": "12px",
|
|
89
|
+
"border": "1px solid #ddd",
|
|
90
|
+
"borderRadius": "4px",
|
|
91
|
+
"boxSizing": "border-box"
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
{errorDisplay}
|
|
95
|
+
<button
|
|
96
|
+
type="submit"
|
|
97
|
+
style={{
|
|
98
|
+
"width": "100%",
|
|
99
|
+
"padding": "10px",
|
|
100
|
+
"background": "#3b82f6",
|
|
101
|
+
"color": "#ffffff",
|
|
102
|
+
"border": "none",
|
|
103
|
+
"borderRadius": "4px",
|
|
104
|
+
"cursor": "pointer",
|
|
105
|
+
"fontWeight": "600"
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
Sign Up
|
|
109
|
+
</button>
|
|
110
|
+
</form>
|
|
111
|
+
<p
|
|
112
|
+
style={{
|
|
113
|
+
"textAlign": "center",
|
|
114
|
+
"marginTop": "16px",
|
|
115
|
+
"fontSize": "14px"
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
Have an account?
|
|
119
|
+
{" "}
|
|
120
|
+
<Link to="/login">
|
|
121
|
+
Login
|
|
122
|
+
</Link>
|
|
123
|
+
</p>
|
|
124
|
+
</div>
|
|
125
|
+
</div>;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Utility functions for formatting
|
|
2
|
+
# Demonstrates: def:pub exports, string methods
|
|
3
|
+
cl {
|
|
4
|
+
# Format number as currency - demonstrates string methods
|
|
5
|
+
def:pub formatCurrency(amount: float) -> str {
|
|
6
|
+
# Use toFixed for decimal formatting
|
|
7
|
+
formatted = amount.toFixed(2);
|
|
8
|
+
return "$" + formatted;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
# Format ISO date string to readable format
|
|
12
|
+
def:pub formatDate(dateStr: str) -> str {
|
|
13
|
+
date = Reflect.construct(Date, [dateStr]);
|
|
14
|
+
return date.toLocaleDateString(
|
|
15
|
+
"en-US", {"month": "short", "day": "numeric", "year": "numeric"}
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# Capitalize first letter of string
|
|
20
|
+
def:pub capitalize(text: str) -> str {
|
|
21
|
+
if text.length == 0 {
|
|
22
|
+
return text;
|
|
23
|
+
}
|
|
24
|
+
return text[0].toUpperCase() + text.slice(1).toLowerCase();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Truncate string with ellipsis
|
|
28
|
+
def:pub truncate(text: str, maxLength: int) -> str {
|
|
29
|
+
if text.length <= maxLength {
|
|
30
|
+
return text;
|
|
31
|
+
}
|
|
32
|
+
return text.slice(0, maxLength) + "...";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Format large numbers with K/M suffix
|
|
36
|
+
def:pub formatCompact(num: float) -> str {
|
|
37
|
+
if num >= 1000000 {
|
|
38
|
+
divided = num / 1000000;
|
|
39
|
+
rounded = Math.round(divided * 10) / 10;
|
|
40
|
+
return (rounded.toString().concat("M"));
|
|
41
|
+
}
|
|
42
|
+
if num >= 1000 {
|
|
43
|
+
divided = num / 1000;
|
|
44
|
+
rounded = Math.round(divided * 10) / 10;
|
|
45
|
+
return rounded.toString().concat("K");
|
|
46
|
+
}
|
|
47
|
+
return Math.round(num).toString();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Pages
|
|
2
|
+
cl import ".styles.css";
|
|
3
|
+
|
|
4
|
+
cl {
|
|
5
|
+
def:pub app -> any {
|
|
6
|
+
has count: int = 0;
|
|
7
|
+
|
|
8
|
+
can with count entry {
|
|
9
|
+
console.log("Count: ", count);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return
|
|
13
|
+
<div
|
|
14
|
+
style={{
|
|
15
|
+
padding: "20px",
|
|
16
|
+
textAlign: "center",
|
|
17
|
+
fontFamily: "Arial, sans-serif"
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
<h1>
|
|
21
|
+
🍔 Burger Counter App
|
|
22
|
+
</h1>
|
|
23
|
+
<img
|
|
24
|
+
src="/static/assets/burger.png"
|
|
25
|
+
alt="Delicious Burger"
|
|
26
|
+
style={{
|
|
27
|
+
width: "200px",
|
|
28
|
+
height: "auto",
|
|
29
|
+
margin: "20px 0",
|
|
30
|
+
borderRadius: "10px",
|
|
31
|
+
boxShadow: "0 4px 8px rgba(0,0,0,0.2)"
|
|
32
|
+
}}
|
|
33
|
+
/>
|
|
34
|
+
<p style={{fontSize: "18px", margin: "20px 0"}}>
|
|
35
|
+
You've clicked the burger
|
|
36
|
+
<strong>
|
|
37
|
+
{count}
|
|
38
|
+
</strong>
|
|
39
|
+
times!
|
|
40
|
+
</p>
|
|
41
|
+
<button
|
|
42
|
+
onClick={lambda e: any -> None { count = count + 1;}}
|
|
43
|
+
style={{
|
|
44
|
+
padding: "10px 20px",
|
|
45
|
+
fontSize: "16px",
|
|
46
|
+
backgroundColor: "#ff6b35",
|
|
47
|
+
color: "white",
|
|
48
|
+
border: "none",
|
|
49
|
+
borderRadius: "5px",
|
|
50
|
+
cursor: "pointer",
|
|
51
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)"
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
Click the Burger! 🍔
|
|
55
|
+
</button>
|
|
56
|
+
<h2 style={{marginTop: "40px", marginBottom: "20px"}}>
|
|
57
|
+
CSS Asset Examples
|
|
58
|
+
</h2>
|
|
59
|
+
<div className="container">
|
|
60
|
+
<h3
|
|
61
|
+
style={{
|
|
62
|
+
color: "white",
|
|
63
|
+
textShadow: "2px 2px 4px rgba(0,0,0,0.5)"
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
Background Image Example
|
|
67
|
+
</h3>
|
|
68
|
+
<p
|
|
69
|
+
style={{
|
|
70
|
+
color: "white",
|
|
71
|
+
textShadow: "2px 2px 4px rgba(0,0,0,0.5)"
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
This container uses the burger image as a background via CSS
|
|
75
|
+
</p>
|
|
76
|
+
</div>
|
|
77
|
+
<div className="card">
|
|
78
|
+
<h3>
|
|
79
|
+
Image in Card
|
|
80
|
+
</h3>
|
|
81
|
+
<img
|
|
82
|
+
src="/static/assets/burger.png"
|
|
83
|
+
alt="Burger in Card"
|
|
84
|
+
className="burgerImage"
|
|
85
|
+
/>
|
|
86
|
+
<p style={{marginTop: "15px", color: "#666"}}>
|
|
87
|
+
This image is displayed within a styled card using CSS classes
|
|
88
|
+
</p>
|
|
89
|
+
</div>
|
|
90
|
+
</div>;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Pages
|
|
2
|
+
cl {
|
|
3
|
+
def:pub app -> any {
|
|
4
|
+
has count: int = 0;
|
|
5
|
+
|
|
6
|
+
can with count entry {
|
|
7
|
+
console.log("Count: ", count);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return
|
|
11
|
+
<div
|
|
12
|
+
style={{
|
|
13
|
+
padding: "20px",
|
|
14
|
+
textAlign: "center",
|
|
15
|
+
fontFamily: "Arial, sans-serif"
|
|
16
|
+
}}
|
|
17
|
+
>
|
|
18
|
+
<h1>
|
|
19
|
+
🍔 Burger Counter App
|
|
20
|
+
</h1>
|
|
21
|
+
<img
|
|
22
|
+
src="/static/assets/burger.png"
|
|
23
|
+
alt="Delicious Burger"
|
|
24
|
+
style={{
|
|
25
|
+
width: "200px",
|
|
26
|
+
height: "auto",
|
|
27
|
+
margin: "20px 0",
|
|
28
|
+
borderRadius: "10px",
|
|
29
|
+
boxShadow: "0 4px 8px rgba(0,0,0,0.2)"
|
|
30
|
+
}}
|
|
31
|
+
/>
|
|
32
|
+
<p style={{fontSize: "18px", margin: "20px 0"}}>
|
|
33
|
+
You've clicked the burger
|
|
34
|
+
<strong>
|
|
35
|
+
{count}
|
|
36
|
+
</strong>
|
|
37
|
+
times!
|
|
38
|
+
</p>
|
|
39
|
+
<button
|
|
40
|
+
onClick={lambda e: any -> None { count = count + 1;}}
|
|
41
|
+
style={{
|
|
42
|
+
padding: "10px 20px",
|
|
43
|
+
fontSize: "16px",
|
|
44
|
+
backgroundColor: "#ff6b35",
|
|
45
|
+
color: "white",
|
|
46
|
+
border: "none",
|
|
47
|
+
borderRadius: "5px",
|
|
48
|
+
cursor: "pointer",
|
|
49
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)"
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
Click the Burger! 🍔
|
|
53
|
+
</button>
|
|
54
|
+
</div>;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Pages
|
|
2
|
+
# Import image using the @jac-client/assets alias
|
|
3
|
+
cl import from "@jac-client/assets/burger.png" {
|
|
4
|
+
default as burgerImage
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
cl {
|
|
8
|
+
def:pub app -> any {
|
|
9
|
+
has count: int = 0;
|
|
10
|
+
|
|
11
|
+
can with count entry {
|
|
12
|
+
console.log("Count: ", count);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return
|
|
16
|
+
<div
|
|
17
|
+
style={{
|
|
18
|
+
padding: "20px",
|
|
19
|
+
textAlign: "center",
|
|
20
|
+
fontFamily: "Arial, sans-serif"
|
|
21
|
+
}}
|
|
22
|
+
>
|
|
23
|
+
<h1>
|
|
24
|
+
🍔 Import Alias Example
|
|
25
|
+
</h1>
|
|
26
|
+
<p style={{color: "#666", marginBottom: "20px"}}>
|
|
27
|
+
Using
|
|
28
|
+
<code>
|
|
29
|
+
@jac-client/assets
|
|
30
|
+
</code>
|
|
31
|
+
alias to import assets
|
|
32
|
+
</p>
|
|
33
|
+
<img
|
|
34
|
+
src={burgerImage}
|
|
35
|
+
alt="Delicious Burger"
|
|
36
|
+
style={{
|
|
37
|
+
width: "200px",
|
|
38
|
+
height: "auto",
|
|
39
|
+
margin: "20px 0",
|
|
40
|
+
borderRadius: "10px",
|
|
41
|
+
boxShadow: "0 4px 8px rgba(0,0,0,0.2)"
|
|
42
|
+
}}
|
|
43
|
+
/>
|
|
44
|
+
<p style={{fontSize: "18px", margin: "20px 0"}}>
|
|
45
|
+
You've clicked the burger
|
|
46
|
+
<strong>
|
|
47
|
+
{count}
|
|
48
|
+
</strong>
|
|
49
|
+
times!
|
|
50
|
+
</p>
|
|
51
|
+
<button
|
|
52
|
+
onClick={lambda e: any -> None { count = count + 1;}}
|
|
53
|
+
style={{
|
|
54
|
+
padding: "10px 20px",
|
|
55
|
+
fontSize: "16px",
|
|
56
|
+
backgroundColor: "#ff6b35",
|
|
57
|
+
color: "white",
|
|
58
|
+
border: "none",
|
|
59
|
+
borderRadius: "5px",
|
|
60
|
+
cursor: "pointer",
|
|
61
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)"
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
Click the Burger! 🍔
|
|
65
|
+
</button>
|
|
66
|
+
<div
|
|
67
|
+
style={{
|
|
68
|
+
marginTop: "30px",
|
|
69
|
+
padding: "15px",
|
|
70
|
+
backgroundColor: "#f5f5f5",
|
|
71
|
+
borderRadius: "5px",
|
|
72
|
+
fontSize: "12px",
|
|
73
|
+
textAlign: "left",
|
|
74
|
+
maxWidth: "600px",
|
|
75
|
+
margin: "30px auto"
|
|
76
|
+
}}
|
|
77
|
+
>
|
|
78
|
+
<strong>
|
|
79
|
+
How it works:
|
|
80
|
+
</strong>
|
|
81
|
+
<ul style={{marginTop: "10px", paddingLeft: "20px"}}>
|
|
82
|
+
<li>
|
|
83
|
+
Import using:
|
|
84
|
+
<code>
|
|
85
|
+
climportfrom'@jac-client/assets/burger.png'
|
|
86
|
+
</code>
|
|
87
|
+
</li>
|
|
88
|
+
<li>
|
|
89
|
+
Vite processes the import and generates optimized URLs
|
|
90
|
+
</li>
|
|
91
|
+
<li>
|
|
92
|
+
Assets are automatically copied from
|
|
93
|
+
<code>
|
|
94
|
+
assets/
|
|
95
|
+
</code>
|
|
96
|
+
to
|
|
97
|
+
<code>
|
|
98
|
+
compiled/assets/
|
|
99
|
+
</code>
|
|
100
|
+
during build
|
|
101
|
+
</li>
|
|
102
|
+
<li>
|
|
103
|
+
Automatic hash generation for cache busting
|
|
104
|
+
</li>
|
|
105
|
+
</ul>
|
|
106
|
+
</div>
|
|
107
|
+
</div>;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Pages
|
|
2
|
+
cl {
|
|
3
|
+
def:pub app -> any {
|
|
4
|
+
has count: int = 0;
|
|
5
|
+
|
|
6
|
+
can with count entry {
|
|
7
|
+
console.log("Count: ", count);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return
|
|
11
|
+
<div>
|
|
12
|
+
<h1>
|
|
13
|
+
Hello, World!
|
|
14
|
+
</h1>
|
|
15
|
+
<p>
|
|
16
|
+
Count: {count}
|
|
17
|
+
</p>
|
|
18
|
+
<button onClick={lambda e: any -> None { count = count + 1;}}>
|
|
19
|
+
Increment
|
|
20
|
+
</button>
|
|
21
|
+
</div>;
|
|
22
|
+
}
|
|
23
|
+
}
|