jac-client 0.1.0__py3-none-any.whl → 0.2.1__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 +232 -172
- jac_client/docs/advanced-state.md +1012 -452
- jac_client/docs/asset-serving/intro.md +209 -0
- jac_client/docs/assets/pipe_line-v2.svg +32 -0
- jac_client/docs/assets/pipe_line.png +0 -0
- jac_client/docs/file-system/intro.md +90 -0
- jac_client/docs/guide-example/intro.md +117 -0
- jac_client/docs/guide-example/step-01-setup.md +260 -0
- jac_client/docs/guide-example/step-02-components.md +416 -0
- jac_client/docs/guide-example/step-03-styling.md +478 -0
- jac_client/docs/guide-example/step-04-todo-ui.md +477 -0
- jac_client/docs/guide-example/step-05-local-state.md +530 -0
- jac_client/docs/guide-example/step-06-events.md +750 -0
- jac_client/docs/guide-example/step-07-effects.md +469 -0
- jac_client/docs/guide-example/step-08-walkers.md +534 -0
- jac_client/docs/guide-example/step-09-authentication.md +586 -0
- jac_client/docs/guide-example/step-10-routing.md +540 -0
- jac_client/docs/guide-example/step-11-final.md +964 -0
- jac_client/docs/imports.md +538 -46
- jac_client/docs/lifecycle-hooks.md +517 -297
- jac_client/docs/routing.md +487 -357
- jac_client/docs/styling/intro.md +250 -0
- jac_client/docs/styling/js-styling.md +373 -0
- jac_client/docs/styling/material-ui.md +346 -0
- jac_client/docs/styling/pure-css.md +305 -0
- jac_client/docs/styling/sass.md +409 -0
- jac_client/docs/styling/styled-components.md +401 -0
- jac_client/docs/styling/tailwind.md +303 -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 +67 -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 +27 -0
- jac_client/examples/asset-serving/css-with-image/vite.config.js +29 -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 +43 -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 +27 -0
- jac_client/examples/asset-serving/image-asset/vite.config.js +29 -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 +57 -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 +29 -0
- jac_client/examples/basic/.babelrc +9 -0
- jac_client/examples/basic/README.md +16 -0
- jac_client/examples/basic/app.jac +16 -0
- jac_client/examples/basic/package.json +27 -0
- jac_client/examples/basic/vite.config.js +28 -0
- jac_client/examples/basic-auth/.babelrc +9 -0
- jac_client/examples/basic-auth/README.md +16 -0
- jac_client/examples/basic-auth/app.jac +308 -0
- jac_client/examples/basic-auth/package.json +27 -0
- jac_client/examples/basic-auth/vite.config.js +28 -0
- jac_client/examples/basic-auth-with-router/.babelrc +9 -0
- jac_client/examples/basic-auth-with-router/README.md +60 -0
- jac_client/examples/basic-auth-with-router/app.jac +464 -0
- jac_client/examples/basic-auth-with-router/package.json +28 -0
- jac_client/examples/basic-auth-with-router/vite.config.js +28 -0
- jac_client/examples/basic-full-stack/.babelrc +9 -0
- jac_client/examples/basic-full-stack/README.md +18 -0
- jac_client/examples/basic-full-stack/app.jac +320 -0
- jac_client/examples/basic-full-stack/package.json +28 -0
- jac_client/examples/basic-full-stack/vite.config.js +28 -0
- 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 +63 -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 +28 -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 +82 -0
- jac_client/examples/css-styling/material-ui/package.json +32 -0
- jac_client/examples/css-styling/material-ui/vite.config.js +28 -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 +63 -0
- jac_client/examples/css-styling/pure-css/package.json +28 -0
- jac_client/examples/css-styling/pure-css/styles.css +112 -0
- jac_client/examples/css-styling/pure-css/vite.config.js +28 -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 +63 -0
- jac_client/examples/css-styling/sass-example/package.json +29 -0
- jac_client/examples/css-styling/sass-example/styles.scss +158 -0
- jac_client/examples/css-styling/sass-example/vite.config.js +28 -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 +66 -0
- jac_client/examples/css-styling/styled-components/package.json +29 -0
- jac_client/examples/css-styling/styled-components/styled.js +91 -0
- jac_client/examples/css-styling/styled-components/vite.config.js +28 -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 +64 -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 +30 -0
- jac_client/examples/full-stack-with-auth/.babelrc +9 -0
- jac_client/examples/full-stack-with-auth/README.md +16 -0
- jac_client/examples/full-stack-with-auth/app.jac +735 -0
- jac_client/examples/full-stack-with-auth/package.json +28 -0
- jac_client/examples/full-stack-with-auth/vite.config.js +30 -0
- jac_client/examples/with-router/.babelrc +9 -0
- jac_client/examples/with-router/README.md +17 -0
- jac_client/examples/with-router/app.jac +323 -0
- jac_client/examples/with-router/package.json +28 -0
- jac_client/examples/with-router/vite.config.js +28 -0
- jac_client/plugin/cli.py +95 -179
- jac_client/plugin/client.py +111 -2
- jac_client/plugin/client_runtime.jac +183 -890
- jac_client/plugin/vite_client_bundle.py +185 -205
- jac_client/tests/__init__.py +0 -1
- jac_client/tests/fixtures/{client_app.jac → basic-app/app.jac} +1 -1
- jac_client/tests/fixtures/cl_file/app.cl.jac +38 -0
- jac_client/tests/fixtures/cl_file/app.jac +15 -0
- jac_client/tests/fixtures/{client_app_with_antd.jac → client_app_with_antd/app.jac} +7 -0
- jac_client/tests/fixtures/{js_import.jac → js_import/app.jac} +2 -2
- jac_client/tests/fixtures/{relative_import.jac → relative_import/app.jac} +1 -1
- jac_client/tests/fixtures/{button.jac → relative_import/button.jac} +2 -2
- jac_client/tests/fixtures/spawn_test/app.jac +133 -0
- jac_client/tests/fixtures/{test_fragments_spread.jac → test_fragments_spread/app.jac} +11 -2
- jac_client/tests/test_asset_examples.py +339 -0
- jac_client/tests/test_cl.py +345 -151
- jac_client/tests/test_create_jac_app.py +41 -45
- {jac_client-0.1.0.dist-info → jac_client-0.2.1.dist-info}/METADATA +72 -16
- jac_client-0.2.1.dist-info/RECORD +140 -0
- jac_client/examples/little-x/package-lock.json +0 -2840
- jac_client/examples/todo-app/README.md +0 -82
- jac_client/examples/todo-app/app.jac +0 -683
- jac_client/examples/todo-app/package-lock.json +0 -999
- jac_client/examples/todo-app/package.json +0 -22
- jac_client-0.1.0.dist-info/RECORD +0 -33
- /jac_client/tests/fixtures/{utils.js → js_import/utils.js} +0 -0
- {jac_client-0.1.0.dist-info → jac_client-0.2.1.dist-info}/WHEEL +0 -0
- {jac_client-0.1.0.dist-info → jac_client-0.2.1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// Sass Variables
|
|
2
|
+
$primary-gradient-start: #dbeafe;
|
|
3
|
+
$primary-gradient-end: #e0e7ff;
|
|
4
|
+
$white: #ffffff;
|
|
5
|
+
$gray-800: #1f2937;
|
|
6
|
+
$gray-600: #4b5563;
|
|
7
|
+
$gray-500: #6b7280;
|
|
8
|
+
$green-600: #16a34a;
|
|
9
|
+
$red-500: #ef4444;
|
|
10
|
+
$red-600: #dc2626;
|
|
11
|
+
|
|
12
|
+
// Mixins
|
|
13
|
+
@mixin flex-center {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@mixin button-base {
|
|
20
|
+
color: $white;
|
|
21
|
+
font-weight: bold;
|
|
22
|
+
padding: 0.75rem 1.5rem;
|
|
23
|
+
border-radius: 0.5rem;
|
|
24
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
25
|
+
transition: all 0.2s ease;
|
|
26
|
+
font-size: 1.25rem;
|
|
27
|
+
border: none;
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
|
|
30
|
+
&:hover {
|
|
31
|
+
transform: scale(1.05);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&:active {
|
|
35
|
+
transform: scale(0.95);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@mixin gradient-divider {
|
|
40
|
+
height: 1px;
|
|
41
|
+
background: linear-gradient(to right, transparent, $gray-500, transparent);
|
|
42
|
+
margin-bottom: 1.5rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Container
|
|
46
|
+
.container {
|
|
47
|
+
min-height: 100vh;
|
|
48
|
+
background: linear-gradient(to bottom right, $primary-gradient-start, $primary-gradient-end);
|
|
49
|
+
@include flex-center;
|
|
50
|
+
padding: 1rem;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Card
|
|
54
|
+
.card {
|
|
55
|
+
background-color: $white;
|
|
56
|
+
border-radius: 1rem;
|
|
57
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
58
|
+
padding: 2rem;
|
|
59
|
+
max-width: 28rem;
|
|
60
|
+
width: 100%;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Title
|
|
64
|
+
.title {
|
|
65
|
+
font-size: 1.875rem;
|
|
66
|
+
font-weight: bold;
|
|
67
|
+
color: $gray-800;
|
|
68
|
+
text-align: center;
|
|
69
|
+
margin-bottom: 1.5rem;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Divider
|
|
73
|
+
.divider {
|
|
74
|
+
@include gradient-divider;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Counter Section
|
|
78
|
+
.counterSection {
|
|
79
|
+
text-align: center;
|
|
80
|
+
margin-bottom: 2rem;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.label {
|
|
84
|
+
font-size: 0.875rem;
|
|
85
|
+
font-weight: 600;
|
|
86
|
+
color: $gray-600;
|
|
87
|
+
margin-bottom: 0.5rem;
|
|
88
|
+
text-transform: uppercase;
|
|
89
|
+
letter-spacing: 0.05em;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Count Display with dynamic colors
|
|
93
|
+
.countDisplay {
|
|
94
|
+
font-size: 3.75rem;
|
|
95
|
+
font-weight: bold;
|
|
96
|
+
transition: color 0.3s ease;
|
|
97
|
+
|
|
98
|
+
&.zero {
|
|
99
|
+
color: $gray-800;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
&.positive {
|
|
103
|
+
color: $green-600;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
&.negative {
|
|
107
|
+
color: $red-600;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Button Group
|
|
112
|
+
.buttonGroup {
|
|
113
|
+
@include flex-center;
|
|
114
|
+
gap: 1rem;
|
|
115
|
+
margin-bottom: 1.5rem;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Buttons
|
|
119
|
+
.btn {
|
|
120
|
+
@include button-base;
|
|
121
|
+
|
|
122
|
+
&Decrement {
|
|
123
|
+
background-color: $red-500;
|
|
124
|
+
|
|
125
|
+
&:hover {
|
|
126
|
+
background-color: darken($red-500, 10%);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&Reset {
|
|
131
|
+
background-color: $gray-500;
|
|
132
|
+
|
|
133
|
+
&:hover {
|
|
134
|
+
background-color: darken($gray-500, 10%);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&Increment {
|
|
139
|
+
background-color: $green-600;
|
|
140
|
+
|
|
141
|
+
&:hover {
|
|
142
|
+
background-color: darken($green-600, 10%);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Hint
|
|
148
|
+
.hint {
|
|
149
|
+
text-align: center;
|
|
150
|
+
font-size: 0.875rem;
|
|
151
|
+
color: $gray-500;
|
|
152
|
+
font-style: italic;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
import { defineConfig } from "vite";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
root: ".", // base folder
|
|
10
|
+
build: {
|
|
11
|
+
rollupOptions: {
|
|
12
|
+
input: "build/main.js", // your compiled entry file
|
|
13
|
+
output: {
|
|
14
|
+
entryFileNames: "client.[hash].js", // name of the final js file
|
|
15
|
+
assetFileNames: "[name].[ext]",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
outDir: "dist", // final bundled output
|
|
19
|
+
emptyOutDir: true,
|
|
20
|
+
},
|
|
21
|
+
publicDir: false,
|
|
22
|
+
resolve: {
|
|
23
|
+
alias: {
|
|
24
|
+
"@jac-client/utils": path.resolve(__dirname, "src/client_runtime.js"),
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Pages
|
|
2
|
+
cl import from react {useState, useEffect}
|
|
3
|
+
cl import from .styled {
|
|
4
|
+
Container,
|
|
5
|
+
Card,
|
|
6
|
+
Title,
|
|
7
|
+
Divider,
|
|
8
|
+
CounterSection,
|
|
9
|
+
Label,
|
|
10
|
+
CountDisplay,
|
|
11
|
+
ButtonGroup,
|
|
12
|
+
Button,
|
|
13
|
+
Hint
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
cl {
|
|
17
|
+
def app() -> any {
|
|
18
|
+
let [count, setCount] = useState(0);
|
|
19
|
+
|
|
20
|
+
useEffect(lambda -> None {
|
|
21
|
+
console.log("Count changed: ", count);
|
|
22
|
+
}, [count]);
|
|
23
|
+
|
|
24
|
+
let handleIncrement = lambda e: any -> None {
|
|
25
|
+
setCount(count + 1);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
let handleDecrement = lambda e: any -> None {
|
|
29
|
+
setCount(count - 1);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
let handleReset = lambda e: any -> None {
|
|
33
|
+
setCount(0);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return <Container>
|
|
37
|
+
<Card>
|
|
38
|
+
<Title>Counter Application</Title>
|
|
39
|
+
<Divider></Divider>
|
|
40
|
+
|
|
41
|
+
<CounterSection>
|
|
42
|
+
<Label>Current Count</Label>
|
|
43
|
+
<CountDisplay count={count}>{count}</CountDisplay>
|
|
44
|
+
</CounterSection>
|
|
45
|
+
|
|
46
|
+
<Divider></Divider>
|
|
47
|
+
|
|
48
|
+
<ButtonGroup>
|
|
49
|
+
<Button bgColor="#ef4444" onClick={handleDecrement}>
|
|
50
|
+
-
|
|
51
|
+
</Button>
|
|
52
|
+
<Button bgColor="#6b7280" onClick={handleReset}>
|
|
53
|
+
↻
|
|
54
|
+
</Button>
|
|
55
|
+
<Button bgColor="#22c55e" onClick={handleIncrement}>
|
|
56
|
+
+
|
|
57
|
+
</Button>
|
|
58
|
+
</ButtonGroup>
|
|
59
|
+
|
|
60
|
+
<Hint>
|
|
61
|
+
Click the buttons to increment, decrement, or reset the counter
|
|
62
|
+
</Hint>
|
|
63
|
+
</Card>
|
|
64
|
+
</Container>;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "styled-components",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "npm run compile && vite build",
|
|
7
|
+
"dev": "vite dev",
|
|
8
|
+
"preview": "vite preview",
|
|
9
|
+
"compile": "babel src --out-dir build --extensions \".jsx,.js\" --out-file-extension .js"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"description": "Jac application: styled-components",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"vite": "^6.4.1",
|
|
18
|
+
"@babel/cli": "^7.28.3",
|
|
19
|
+
"@babel/core": "^7.28.5",
|
|
20
|
+
"@babel/preset-env": "^7.28.5",
|
|
21
|
+
"@babel/preset-react": "^7.28.5"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"react": "^19.2.0",
|
|
25
|
+
"react-dom": "^19.2.0",
|
|
26
|
+
"react-router-dom": "^6.30.1",
|
|
27
|
+
"styled-components": "^6.1.13"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
export const Container = styled.div`
|
|
4
|
+
min-height: 100vh;
|
|
5
|
+
background: linear-gradient(to bottom right, #dbeafe, #e0e7ff);
|
|
6
|
+
display: flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
padding: 1rem;
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
export const Card = styled.div`
|
|
13
|
+
background-color: #ffffff;
|
|
14
|
+
border-radius: 1rem;
|
|
15
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
16
|
+
padding: 2rem;
|
|
17
|
+
max-width: 28rem;
|
|
18
|
+
width: 100%;
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
export const Title = styled.h1`
|
|
22
|
+
font-size: 1.875rem;
|
|
23
|
+
font-weight: bold;
|
|
24
|
+
color: #1f2937;
|
|
25
|
+
text-align: center;
|
|
26
|
+
margin-bottom: 1.5rem;
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
export const Divider = styled.div`
|
|
30
|
+
height: 1px;
|
|
31
|
+
background: linear-gradient(to right, transparent, #d1d5db, transparent);
|
|
32
|
+
margin-bottom: 1.5rem;
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
export const CounterSection = styled.div`
|
|
36
|
+
text-align: center;
|
|
37
|
+
margin-bottom: 2rem;
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
export const Label = styled.div`
|
|
41
|
+
font-size: 0.875rem;
|
|
42
|
+
font-weight: 600;
|
|
43
|
+
color: #4b5563;
|
|
44
|
+
margin-bottom: 0.5rem;
|
|
45
|
+
text-transform: uppercase;
|
|
46
|
+
letter-spacing: 0.05em;
|
|
47
|
+
`;
|
|
48
|
+
|
|
49
|
+
export const CountDisplay = styled.div`
|
|
50
|
+
font-size: 3.75rem;
|
|
51
|
+
font-weight: bold;
|
|
52
|
+
transition: color 0.3s ease;
|
|
53
|
+
color: ${props => props.count === 0 ? "#1f2937" : (props.count > 0 ? "#16a34a" : "#dc2626")};
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
export const ButtonGroup = styled.div`
|
|
57
|
+
display: flex;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
align-items: center;
|
|
60
|
+
gap: 1rem;
|
|
61
|
+
margin-bottom: 1.5rem;
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
export const Button = styled.button`
|
|
65
|
+
color: #ffffff;
|
|
66
|
+
font-weight: bold;
|
|
67
|
+
padding: 0.75rem 1.5rem;
|
|
68
|
+
border-radius: 0.5rem;
|
|
69
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
70
|
+
transition: all 0.2s ease;
|
|
71
|
+
font-size: 1.25rem;
|
|
72
|
+
border: none;
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
background-color: ${props => props.bgColor};
|
|
75
|
+
|
|
76
|
+
&:hover {
|
|
77
|
+
transform: scale(1.05);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
&:active {
|
|
81
|
+
transform: scale(0.95);
|
|
82
|
+
}
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
export const Hint = styled.div`
|
|
86
|
+
text-align: center;
|
|
87
|
+
font-size: 0.875rem;
|
|
88
|
+
color: #6b7280;
|
|
89
|
+
font-style: italic;
|
|
90
|
+
`;
|
|
91
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
import { defineConfig } from "vite";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
root: ".", // base folder
|
|
10
|
+
build: {
|
|
11
|
+
rollupOptions: {
|
|
12
|
+
input: "build/main.js", // your compiled entry file
|
|
13
|
+
output: {
|
|
14
|
+
entryFileNames: "client.[hash].js", // name of the final js file
|
|
15
|
+
assetFileNames: "[name].[ext]",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
outDir: "dist", // final bundled output
|
|
19
|
+
emptyOutDir: true,
|
|
20
|
+
},
|
|
21
|
+
publicDir: false,
|
|
22
|
+
resolve: {
|
|
23
|
+
alias: {
|
|
24
|
+
"@jac-client/utils": path.resolve(__dirname, "src/client_runtime.js"),
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Pages
|
|
2
|
+
cl import from react {useState, useEffect}
|
|
3
|
+
cl import ".global.css";
|
|
4
|
+
cl {
|
|
5
|
+
def app() -> any {
|
|
6
|
+
let [count, setCount] = useState(0);
|
|
7
|
+
|
|
8
|
+
useEffect(lambda -> None {
|
|
9
|
+
console.log("Count changed: ", count);
|
|
10
|
+
}, [count]);
|
|
11
|
+
|
|
12
|
+
let handleIncrement = lambda e: any -> None {
|
|
13
|
+
setCount(count + 1);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
let handleDecrement = lambda e: any -> None {
|
|
17
|
+
setCount(count - 1);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
let handleReset = lambda e: any -> None {
|
|
21
|
+
setCount(0);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
let countColorClass = "text-gray-800" if count == 0 else ("text-green-600" if count > 0 else "text-red-600");
|
|
25
|
+
|
|
26
|
+
return <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 flex items-center justify-center p-4">
|
|
27
|
+
<div className="bg-white rounded-2xl shadow-2xl p-8 max-w-md w-full">
|
|
28
|
+
<h1 className="text-3xl font-bold text-gray-800 text-center mb-6">Counter Application</h1>
|
|
29
|
+
<div className="h-px bg-gradient-to-r from-transparent via-gray-300 to-transparent mb-6"></div>
|
|
30
|
+
|
|
31
|
+
<div className="text-center mb-8">
|
|
32
|
+
<div className="text-sm font-semibold text-gray-600 mb-2 uppercase tracking-wide">Current Count</div>
|
|
33
|
+
<div className={"text-6xl font-bold " + countColorClass + " transition-colors duration-300"}>
|
|
34
|
+
{count}
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div className="h-px bg-gradient-to-r from-transparent via-gray-300 to-transparent mb-6"></div>
|
|
39
|
+
|
|
40
|
+
<div className="flex justify-center items-center gap-4 mb-6">
|
|
41
|
+
<button
|
|
42
|
+
className="bg-red-500 hover:bg-red-600 text-white font-bold py-3 px-6 rounded-lg shadow-lg transition-all duration-200 transform hover:scale-105 active:scale-95 text-xl"
|
|
43
|
+
onClick={handleDecrement}>
|
|
44
|
+
-
|
|
45
|
+
</button>
|
|
46
|
+
<button
|
|
47
|
+
className="bg-gray-500 hover:bg-gray-600 text-white font-bold py-3 px-6 rounded-lg shadow-lg transition-all duration-200 transform hover:scale-105 active:scale-95 text-xl"
|
|
48
|
+
onClick={handleReset}>
|
|
49
|
+
↻
|
|
50
|
+
</button>
|
|
51
|
+
<button
|
|
52
|
+
className="bg-green-500 hover:bg-green-600 text-white font-bold py-3 px-6 rounded-lg shadow-lg transition-all duration-200 transform hover:scale-105 active:scale-95 text-xl"
|
|
53
|
+
onClick={handleIncrement}>
|
|
54
|
+
+
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div className="text-center text-sm text-gray-500 italic">
|
|
59
|
+
Click the buttons to increment, decrement, or reset the counter
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tailwind-example",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "npm run compile && vite build",
|
|
7
|
+
"dev": "vite dev",
|
|
8
|
+
"preview": "vite preview",
|
|
9
|
+
"compile": "babel src --out-dir build --extensions \".jsx,.js\" --out-file-extension .js"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"description": "Jac application: tailwind-example",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@babel/cli": "^7.28.3",
|
|
18
|
+
"@babel/core": "^7.28.5",
|
|
19
|
+
"@babel/preset-env": "^7.28.5",
|
|
20
|
+
"@babel/preset-react": "^7.28.5",
|
|
21
|
+
"vite": "^6.4.1"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@tailwindcss/vite": "^4.1.17",
|
|
25
|
+
"react": "^19.2.0",
|
|
26
|
+
"react-dom": "^19.2.0",
|
|
27
|
+
"react-router-dom": "^6.30.1",
|
|
28
|
+
"tailwindcss": "^4.1.17"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
import { defineConfig } from "vite";
|
|
3
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
root: ".", // base folder
|
|
11
|
+
build: {
|
|
12
|
+
rollupOptions: {
|
|
13
|
+
input: "build/main.js", // your compiled entry file
|
|
14
|
+
output: {
|
|
15
|
+
entryFileNames: "client.[hash].js", // name of the final js file
|
|
16
|
+
assetFileNames: "[name].[ext]",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
outDir: "dist", // final bundled output
|
|
20
|
+
emptyOutDir: true,
|
|
21
|
+
},
|
|
22
|
+
plugins: [ tailwindcss(), ],
|
|
23
|
+
publicDir: false,
|
|
24
|
+
resolve: {
|
|
25
|
+
alias: {
|
|
26
|
+
"@jac-client/utils": path.resolve(__dirname, "src/client_runtime.js"),
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|