jac-client 0.2.6__tar.gz → 0.2.8__tar.gz

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 (104) hide show
  1. {jac_client-0.2.6 → jac_client-0.2.8}/PKG-INFO +16 -7
  2. {jac_client-0.2.6 → jac_client-0.2.8}/README.md +14 -5
  3. jac_client-0.2.8/jac_client/examples/all-in-one/app.jac +573 -0
  4. jac_client-0.2.8/jac_client/examples/all-in-one/components/CategoryFilter.jac +35 -0
  5. jac_client-0.2.8/jac_client/examples/all-in-one/components/Header.jac +13 -0
  6. jac_client-0.2.8/jac_client/examples/all-in-one/components/ProfitOverview.jac +50 -0
  7. jac_client-0.2.8/jac_client/examples/all-in-one/components/Summary.jac +53 -0
  8. jac_client-0.2.8/jac_client/examples/all-in-one/components/TransactionForm.jac +158 -0
  9. jac_client-0.2.8/jac_client/examples/all-in-one/components/TransactionItem.jac +55 -0
  10. jac_client-0.2.8/jac_client/examples/all-in-one/components/TransactionList.jac +37 -0
  11. jac_client-0.2.8/jac_client/examples/all-in-one/components/navigation.jac +132 -0
  12. jac_client-0.2.8/jac_client/examples/all-in-one/constants/categories.jac +37 -0
  13. jac_client-0.2.8/jac_client/examples/all-in-one/constants/clients.jac +13 -0
  14. jac_client-0.2.8/jac_client/examples/all-in-one/context/BudgetContext.jac +28 -0
  15. jac_client-0.2.8/jac_client/examples/all-in-one/hooks/useBudget.jac +116 -0
  16. jac_client-0.2.8/jac_client/examples/all-in-one/hooks/useLocalStorage.jac +36 -0
  17. jac_client-0.2.8/jac_client/examples/all-in-one/pages/BudgetPlanner.cl.jac +70 -0
  18. jac_client-0.2.8/jac_client/examples/all-in-one/pages/BudgetPlanner.jac +126 -0
  19. jac_client-0.2.8/jac_client/examples/all-in-one/pages/FeaturesTest.cl.jac +552 -0
  20. jac_client-0.2.8/jac_client/examples/all-in-one/pages/FeaturesTest.jac +126 -0
  21. jac_client-0.2.8/jac_client/examples/all-in-one/pages/LandingPage.jac +101 -0
  22. jac_client-0.2.8/jac_client/examples/all-in-one/pages/loginPage.jac +132 -0
  23. jac_client-0.2.8/jac_client/examples/all-in-one/pages/nestedDemo.jac +61 -0
  24. jac_client-0.2.8/jac_client/examples/all-in-one/pages/notFound.jac +24 -0
  25. jac_client-0.2.8/jac_client/examples/all-in-one/pages/signupPage.jac +133 -0
  26. jac_client-0.2.8/jac_client/examples/all-in-one/utils/formatters.jac +52 -0
  27. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/asset-serving/css-with-image/src/app.jac +3 -3
  28. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/asset-serving/image-asset/src/app.jac +3 -3
  29. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/asset-serving/import-alias/src/app.jac +3 -3
  30. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/basic/src/app.jac +3 -3
  31. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/basic-auth/src/app.jac +31 -37
  32. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/basic-auth-with-router/src/app.jac +16 -16
  33. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/basic-full-stack/src/app.jac +24 -30
  34. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/css-styling/js-styling/src/app.jac +5 -5
  35. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/css-styling/material-ui/src/app.jac +5 -5
  36. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/css-styling/pure-css/src/app.jac +5 -5
  37. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/css-styling/sass-example/src/app.jac +5 -5
  38. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/css-styling/styled-components/src/app.jac +5 -5
  39. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/css-styling/tailwind-example/src/app.jac +5 -5
  40. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/full-stack-with-auth/src/app.jac +16 -16
  41. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/ts-support/src/app.jac +4 -4
  42. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/with-router/src/app.jac +4 -4
  43. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/cli.jac +160 -203
  44. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/client.jac +8 -15
  45. jac_client-0.2.8/jac_client/plugin/client_runtime.cl.jac +42 -0
  46. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/impl/client.impl.jac +85 -26
  47. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/impl/client_runtime.impl.jac +27 -9
  48. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/plugin_config.jac +11 -11
  49. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/compiler.jac +2 -1
  50. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/impl/babel_processor.impl.jac +22 -17
  51. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/impl/compiler.impl.jac +55 -18
  52. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/impl/vite_bundler.impl.jac +215 -102
  53. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/package_installer.jac +1 -1
  54. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/vite_bundler.jac +9 -1
  55. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/conftest.py +10 -8
  56. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/fixtures/spawn_test/app.jac +15 -18
  57. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/fixtures/with-ts/app.jac +4 -4
  58. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/test_cli.py +105 -49
  59. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/test_it.py +297 -82
  60. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client.egg-info/PKG-INFO +16 -7
  61. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client.egg-info/SOURCES.txt +26 -3
  62. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client.egg-info/requires.txt +1 -1
  63. {jac_client-0.2.6 → jac_client-0.2.8}/pyproject.toml +2 -2
  64. jac_client-0.2.6/jac_client/examples/all-in-one/src/app.jac +0 -841
  65. jac_client-0.2.6/jac_client/plugin/client_runtime.cl.jac +0 -38
  66. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/all-in-one/assets/workers/worker.py +0 -0
  67. {jac_client-0.2.6/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/button.jac +0 -0
  68. {jac_client-0.2.6/jac_client/examples/all-in-one/src → jac_client-0.2.8/jac_client/examples/all-in-one}/components/button.jac +0 -0
  69. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/little-x/src/app.jac +0 -0
  70. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/little-x/src/submit-button.jac +0 -0
  71. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +0 -0
  72. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-advance/src/app.jac +0 -0
  73. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +0 -0
  74. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +0 -0
  75. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +0 -0
  76. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-basic/src/app.jac +0 -0
  77. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-basic/src/button.jac +0 -0
  78. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/examples/nested-folders/nested-basic/src/components/button.jac +0 -0
  79. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/impl/vite_client_bundle.impl.jac +0 -0
  80. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/__init__.jac +0 -0
  81. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/asset_processor.jac +0 -0
  82. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/babel_processor.jac +0 -0
  83. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/config_loader.jac +0 -0
  84. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/impl/asset_processor.impl.jac +0 -0
  85. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/impl/config_loader.impl.jac +0 -0
  86. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/impl/import_processor.impl.jac +0 -0
  87. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/impl/jac_to_js.impl.jac +0 -0
  88. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/impl/package_installer.impl.jac +0 -0
  89. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/import_processor.jac +0 -0
  90. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/src/jac_to_js.jac +0 -0
  91. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/plugin/vite_client_bundle.jac +0 -0
  92. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/__init__.py +0 -0
  93. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/fixtures/basic-app/app.jac +0 -0
  94. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/fixtures/cl_file/app.cl.jac +0 -0
  95. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/fixtures/cl_file/app.jac +0 -0
  96. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/fixtures/client_app_with_antd/app.jac +0 -0
  97. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/fixtures/js_import/app.jac +0 -0
  98. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/fixtures/relative_import/app.jac +0 -0
  99. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/fixtures/relative_import/button.jac +0 -0
  100. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client/tests/fixtures/test_fragments_spread/app.jac +0 -0
  101. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client.egg-info/dependency_links.txt +0 -0
  102. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client.egg-info/entry_points.txt +0 -0
  103. {jac_client-0.2.6 → jac_client-0.2.8}/jac_client.egg-info/top_level.txt +0 -0
  104. {jac_client-0.2.6 → jac_client-0.2.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jac-client
3
- Version: 0.2.6
3
+ Version: 0.2.8
4
4
  Summary: Build full-stack web applications with Jac - one language for frontend and backend.
5
5
  Author-email: Jason Mars <jason@mars.ninja>
6
6
  Maintainer-email: Jason Mars <jason@mars.ninja>
@@ -11,7 +11,7 @@ Project-URL: Documentation, https://jac-lang.org
11
11
  Keywords: jac,jaclang,jaseci,frontend,full-stack,web-development
12
12
  Requires-Python: >=3.12
13
13
  Description-Content-Type: text/markdown
14
- Requires-Dist: jaclang==0.9.6
14
+ Requires-Dist: jaclang==0.9.8
15
15
  Provides-Extra: dev
16
16
  Requires-Dist: python-dotenv==1.0.1; extra == "dev"
17
17
  Requires-Dist: pytest==8.3.5; extra == "dev"
@@ -28,7 +28,7 @@ Jac Client enables you to write React-like components, manage state, and build i
28
28
 
29
29
  - **Single Language**: Write frontend and backend in Jac
30
30
  - **No HTTP Client**: Use `jacSpawn()` instead of fetch/axios
31
- - **React Hooks**: Use standard React `useState` and `useEffect` hooks
31
+ - **React Hooks**: Use standard React `useState` and `useEffect` hooks (useState is auto-injected when using `has` variables)
32
32
  - **Component-Based**: Build reusable UI components with JSX
33
33
  - **Graph Database**: Built-in graph data model eliminates need for SQL/NoSQL
34
34
  - **Type Safety**: Type checking across frontend and backend
@@ -49,10 +49,12 @@ pip install jac-client
49
49
  ```bash
50
50
  jac create --cl my-app
51
51
  cd my-app
52
- jac serve src/app.jac
52
+ jac start src/app.jac
53
53
  ```
54
54
 
55
- Visit `http://localhost:8000/page/app` to see your app!
55
+ Visit `http://localhost:8000` to see your app! (The `app` component is served at the root by default.)
56
+
57
+ You can also access the app at `http://localhost:8000/cl/app`.
56
58
 
57
59
  > **Note**: The `--cl` flag creates a client-side project with an organized folder structure. Without `--cl`, `jac create` creates a standard Jac project.
58
60
 
@@ -75,10 +77,13 @@ For detailed guides and tutorials, see the **[docs folder](jac_client/docs/)**:
75
77
  ### Simple Counter with React Hooks
76
78
 
77
79
  ```jac
78
- cl import from react { useState, useEffect }
80
+ # Note: useState is auto-injected when using has variables in cl blocks
81
+ # Only useEffect needs explicit import
82
+ cl import from react { useEffect }
79
83
 
80
84
  cl {
81
85
  def Counter() -> any {
86
+ # useState is automatically available - no import needed!
82
87
  [count, setCount] = useState(0);
83
88
 
84
89
  useEffect(lambda -> None {
@@ -101,10 +106,13 @@ cl {
101
106
  }
102
107
  ```
103
108
 
109
+ > **Note:** When using `has` variables in `cl {}` blocks or `.cl.jac` files, the `useState` import is automatically injected. You only need to explicitly import other hooks like `useEffect`.
110
+
104
111
  ### Full-Stack Todo App
105
112
 
106
113
  ```jac
107
- cl import from react { useState, useEffect }
114
+ # useState is auto-injected, only import useEffect
115
+ cl import from react { useEffect }
108
116
  cl import from '@jac-client/utils' { jacSpawn }
109
117
 
110
118
  # Backend: Jac nodes and walkers
@@ -130,6 +138,7 @@ walker read_todos {
130
138
  # Frontend: React component
131
139
  cl {
132
140
  def app() -> any {
141
+ # useState is automatically available - no import needed!
133
142
  [todos, setTodos] = useState([]);
134
143
 
135
144
  useEffect(lambda -> None {
@@ -10,7 +10,7 @@ Jac Client enables you to write React-like components, manage state, and build i
10
10
 
11
11
  - **Single Language**: Write frontend and backend in Jac
12
12
  - **No HTTP Client**: Use `jacSpawn()` instead of fetch/axios
13
- - **React Hooks**: Use standard React `useState` and `useEffect` hooks
13
+ - **React Hooks**: Use standard React `useState` and `useEffect` hooks (useState is auto-injected when using `has` variables)
14
14
  - **Component-Based**: Build reusable UI components with JSX
15
15
  - **Graph Database**: Built-in graph data model eliminates need for SQL/NoSQL
16
16
  - **Type Safety**: Type checking across frontend and backend
@@ -31,10 +31,12 @@ pip install jac-client
31
31
  ```bash
32
32
  jac create --cl my-app
33
33
  cd my-app
34
- jac serve src/app.jac
34
+ jac start src/app.jac
35
35
  ```
36
36
 
37
- Visit `http://localhost:8000/page/app` to see your app!
37
+ Visit `http://localhost:8000` to see your app! (The `app` component is served at the root by default.)
38
+
39
+ You can also access the app at `http://localhost:8000/cl/app`.
38
40
 
39
41
  > **Note**: The `--cl` flag creates a client-side project with an organized folder structure. Without `--cl`, `jac create` creates a standard Jac project.
40
42
 
@@ -57,10 +59,13 @@ For detailed guides and tutorials, see the **[docs folder](jac_client/docs/)**:
57
59
  ### Simple Counter with React Hooks
58
60
 
59
61
  ```jac
60
- cl import from react { useState, useEffect }
62
+ # Note: useState is auto-injected when using has variables in cl blocks
63
+ # Only useEffect needs explicit import
64
+ cl import from react { useEffect }
61
65
 
62
66
  cl {
63
67
  def Counter() -> any {
68
+ # useState is automatically available - no import needed!
64
69
  [count, setCount] = useState(0);
65
70
 
66
71
  useEffect(lambda -> None {
@@ -83,10 +88,13 @@ cl {
83
88
  }
84
89
  ```
85
90
 
91
+ > **Note:** When using `has` variables in `cl {}` blocks or `.cl.jac` files, the `useState` import is automatically injected. You only need to explicitly import other hooks like `useEffect`.
92
+
86
93
  ### Full-Stack Todo App
87
94
 
88
95
  ```jac
89
- cl import from react { useState, useEffect }
96
+ # useState is auto-injected, only import useEffect
97
+ cl import from react { useEffect }
90
98
  cl import from '@jac-client/utils' { jacSpawn }
91
99
 
92
100
  # Backend: Jac nodes and walkers
@@ -112,6 +120,7 @@ walker read_todos {
112
120
  # Frontend: React component
113
121
  cl {
114
122
  def app() -> any {
123
+ # useState is automatically available - no import needed!
115
124
  [todos, setTodos] = useState([]);
116
125
 
117
126
  useEffect(lambda -> None {
@@ -0,0 +1,573 @@
1
+ import from datetime { datetime, timedelta }
2
+
3
+ #
4
+ # Basic backend walkers
5
+ #
6
+ node Todo {
7
+ has text: str,
8
+ done: bool = False;
9
+ }
10
+
11
+ walker create_todo {
12
+ has text: str;
13
+
14
+ can create with `root entry {
15
+ new_todo = here ++> Todo(text=self.text);
16
+ report new_todo ;
17
+ }
18
+ }
19
+
20
+ walker ping_server {
21
+ can ping with `root entry {
22
+ report "pong from backend!" ;
23
+ }
24
+ }
25
+
26
+ walker get_server_message {
27
+ can info with `root entry {
28
+ report "hello from a basic walker!" ;
29
+ }
30
+ }
31
+
32
+
33
+
34
+ # Features Test Page - Backend Logic
35
+ # This file is intentionally kept empty to demonstrate the separation of concerns
36
+ # where UI logic resides in .cl.jac files and backend walker logic in app.jac
37
+
38
+ # All walker implementations for this feature are in src/app.jac
39
+ # This demonstrates that you can have separate .jac files for different purposes
40
+ # Features Test - Backend Walkers
41
+ # This file demonstrates walker functionality for testing various JAC features
42
+
43
+
44
+ # Node definition for storing test data
45
+ node TestData {
46
+ has message: str;
47
+ has count: int = 0;
48
+ has created_at: str = "";
49
+ }
50
+
51
+ # Walker: Create test data
52
+ walker create_test_data {
53
+ has message: str;
54
+
55
+ can create with `root entry {
56
+ new_data = here ++> TestData(
57
+ message=self.message,
58
+ count=1,
59
+ created_at=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
60
+ );
61
+ report new_data;
62
+ }
63
+ }
64
+
65
+ # Walker: Read all test data
66
+ walker read_test_data {
67
+ can read with `root entry {
68
+ visit [-->(`?TestData)];
69
+ }
70
+
71
+ can report_data with exit {
72
+ report here;
73
+ }
74
+ }
75
+
76
+ # Walker: Update test data
77
+ walker update_test_data {
78
+ has new_message: str;
79
+
80
+ can update with TestData entry {
81
+ here.message = self.new_message;
82
+ here.count = here.count + 1;
83
+ report here;
84
+ }
85
+ }
86
+
87
+ # Walker: Delete test data
88
+ walker delete_test_data {
89
+ can delete with TestData entry {
90
+ del here;
91
+ report {"status": "deleted"};
92
+ }
93
+ }
94
+
95
+ # Walker: String manipulation test
96
+ walker test_string_methods {
97
+ has input_text: str;
98
+
99
+ can process with `root entry {
100
+ result = {
101
+ "original": self.input_text,
102
+ "uppercase": self.input_text.upper(),
103
+ "lowercase": self.input_text.lower(),
104
+ "capitalized": self.input_text.capitalize(),
105
+ "reversed": self.input_text[::-1],
106
+ "length": len(self.input_text),
107
+ "words": self.input_text.split(),
108
+ "trimmed": self.input_text.strip(),
109
+ "replaced": self.input_text.replace("test", "demo")
110
+ };
111
+ report result;
112
+ }
113
+ }
114
+
115
+ # Walker: Array/List operations test
116
+ walker test_list_operations {
117
+ has numbers: list;
118
+
119
+ can process with `root entry {
120
+ result = {
121
+ "original": self.numbers,
122
+ "sorted": sorted(self.numbers),
123
+ "reversed": list(reversed(self.numbers)),
124
+ "sum": sum(self.numbers),
125
+ "max": max(self.numbers) if len(self.numbers) > 0 else 0,
126
+ "min": min(self.numbers) if len(self.numbers) > 0 else 0,
127
+ "length": len(self.numbers),
128
+ "doubled": [x * 2 for x in self.numbers]
129
+ };
130
+ report result;
131
+ }
132
+ }
133
+
134
+ # Walker: Complex data processing
135
+ walker process_complex_data {
136
+ has items: list;
137
+
138
+ can process with `root entry {
139
+ processed = [];
140
+ for item in self.items {
141
+ processed.append({
142
+ "id": item.get("id", 0),
143
+ "name": item.get("name", "").upper(),
144
+ "value": item.get("value", 0) * 2,
145
+ "processed_at": datetime.now().strftime("%H:%M:%S")
146
+ });
147
+ }
148
+
149
+ result = {
150
+ "original_count": len(self.items),
151
+ "processed_count": len(processed),
152
+ "items": processed,
153
+ "total_value": sum([p["value"] for p in processed])
154
+ };
155
+
156
+ report result;
157
+ }
158
+ }
159
+
160
+
161
+ #
162
+ # Combined example: auth + routing + CSS styling + asset serving + nested folder imports
163
+ #
164
+ cl import from react { useEffect, useRef }
165
+ cl import from "@jac-client/utils" {
166
+ Router,
167
+ Routes,
168
+ Route,
169
+ Link,
170
+ useNavigate,
171
+ Navigate,
172
+ jacIsLoggedIn
173
+
174
+ }
175
+
176
+ # Pure CSS + asset-in-CSS example
177
+ cl import ".styles.css";
178
+
179
+ # Login Page
180
+ cl import from .pages.loginPage { LoginPage }
181
+
182
+ # Signup Page
183
+ cl import from .pages.signupPage { SignupPage }
184
+
185
+ # Simple 404 page
186
+ cl import from .pages.notFound { NotFound }
187
+
188
+ # Navigation component with active link styling and auth
189
+ cl import from .components.navigation { Navigation }
190
+
191
+ # Page showing nested imports from different folders
192
+ cl import from .pages.nestedDemo { NestedImportsDemo }
193
+
194
+ cl import from .pages.FeaturesTest { FeaturesTest }
195
+
196
+ cl import from .pages.LandingPage { LandingPage }
197
+
198
+ cl import from .pages.BudgetPlanner { BudgetPlanner }
199
+
200
+ # Context provider
201
+ cl import from .context.BudgetContext { BudgetProvider }
202
+
203
+
204
+
205
+ # TypeScript component import
206
+ cl import from ".components/Card.tsx" { Card }
207
+
208
+
209
+ # Main app wrapped in Router (same API as with-router/ example)
210
+ cl {
211
+ def:pub HomePage -> any {
212
+ # Check if user is logged in, redirect if not
213
+ if not jacIsLoggedIn() {
214
+ return <Navigate to="/login" />;
215
+ }
216
+ has count: int = 0;
217
+ has pingResult: str = "";
218
+ has serverMessage: str = "";
219
+ has lastTodoMessage: str = "";
220
+
221
+ useEffect(
222
+ lambda -> None{ console.log("Home count changed: ", count);} , [count]
223
+ );
224
+
225
+ # Call simple backend walkers
226
+ async def handlePing -> None {
227
+ result = root spawn ping_server();
228
+ if result.reports and result.reports.length > 0 {
229
+ pingResult = result.reports[0][0];
230
+ }
231
+ }
232
+
233
+ async def loadServerMessage -> None {
234
+ result = root spawn get_server_message();
235
+ if result.reports and result.reports.length > 0 {
236
+ serverMessage = result.reports[0][0];
237
+ }
238
+ }
239
+
240
+ # Create a sample Todo node in the graph with a hardcoded payload
241
+ async def handleCreateSampleTodo -> None {
242
+ result = root spawn create_todo(text="Sample todo from all-in-one app");
243
+ if result.reports and result.reports.length > 0 {
244
+ todo = result.reports[0][0];
245
+ lastTodoMessage = "Created Todo: " + todo.text;
246
+ console.log("Created Todo node:", todo);
247
+ }
248
+ }
249
+
250
+ useEffect(lambda -> None{ loadServerMessage();} , []);
251
+
252
+ # Initialize a Web Worker and handle message-based communication
253
+ workerRef = useRef(None);
254
+ has message: str = "";
255
+
256
+ useEffect(lambda -> None {
257
+ workerRef.current = Reflect.construct(Worker, ["/workers/worker.js"]);
258
+ workerRef.current.onmessage = lambda event: any -> None {
259
+ console.log("Message received from worker:", event.data);
260
+ message = event.data;
261
+ };
262
+ return (lambda -> None {
263
+ workerRef.current.terminate();
264
+ });
265
+ }, []);
266
+ handleClick = lambda -> None {
267
+ workerRef.current.postMessage("");
268
+ };
269
+
270
+ return <div
271
+ style={{
272
+ "padding": "2rem",
273
+ "fontFamily": "system-ui, -apple-system, sans-serif"
274
+ }}
275
+ >
276
+ <h1>
277
+ 🍔 Router + Styling + Assets Demo
278
+ </h1>
279
+ <p>
280
+ This home page combines
281
+ {" "}
282
+ <strong>
283
+ React Router,
284
+ </strong>
285
+ {" "}
286
+ <strong>
287
+ pure CSS styling,
288
+ </strong>
289
+ {" "}
290
+ <strong>
291
+ static assets
292
+ </strong>
293
+ {" "}
294
+ and
295
+ {" "}
296
+ <strong>
297
+ nested folder imports
298
+ </strong>
299
+ </p>
300
+ <div className="container">
301
+ <h2
302
+ style={{
303
+ "color": "white",
304
+ "textShadow": "2px 2px 4px rgba(0,0,0,0.6)"
305
+ }}
306
+ >
307
+ CSS Background Image
308
+ </h2>
309
+ <p
310
+ style={{
311
+ "color": "white",
312
+ "maxWidth": "480px",
313
+ "textShadow": "1px 1px 3px rgba(0,0,0,0.7)"
314
+ }}
315
+ >
316
+ This section uses the burger image as a background via CSS, just like the
317
+ {" "}
318
+ <code>
319
+ asset-serving/css-with-image
320
+ </code>
321
+ {" "}
322
+ example.
323
+ </p>
324
+ </div>
325
+ <Card
326
+ title="TypeScript Card Component"
327
+ description="This card is built with TypeScript and demonstrates type-safe component usage in Jac"
328
+ variant="highlighted"
329
+ >
330
+ <p
331
+ style={{"margin": "0.5rem 0", "color": "#374151"}}
332
+ >
333
+ This is a TypeScript component imported and used in Jac code!
334
+ </p>
335
+ </Card>
336
+ <div className="card">
337
+ <h3>
338
+ Direct &lt;img&gt; asset
339
+ </h3>
340
+ <img
341
+ src="/static/assets/burger.png"
342
+ alt="Burger asset served by Jac"
343
+ className="burgerImage"
344
+ />
345
+ <p
346
+ style={{"marginTop": "0.75rem", "color": "#555"}}
347
+ >
348
+ This image is served from the project
349
+ {" "}
350
+ <code>
351
+ assets/
352
+ </code>
353
+ {" "}
354
+ folder using the
355
+ {" "}
356
+ <code>
357
+ /static/assets/
358
+ </code>
359
+ {" "}
360
+ path.
361
+ </p>
362
+ </div>
363
+ <div
364
+ style={{"marginTop": "2rem"}}
365
+ >
366
+ <h3>
367
+ Counter with pure CSS classes
368
+ </h3>
369
+ <p>
370
+ You've clicked the burger
371
+ {" "}
372
+ <strong>
373
+ {count}
374
+ </strong>
375
+ {" "}
376
+ times.
377
+ </p>
378
+ <button
379
+ onClick={lambda e: any -> None{ count = count + 1;} }
380
+ style={{
381
+ "padding": "0.6rem 1.4rem",
382
+ "fontSize": "1rem",
383
+ "backgroundColor": "#ff6b35",
384
+ "color": "white",
385
+ "border": "none",
386
+ "borderRadius": "6px",
387
+ "cursor": "pointer",
388
+ "boxShadow": "0 2px 4px rgba(0,0,0,0.2)"
389
+ }}
390
+ >
391
+ Click the Burger! 🍔
392
+ </button>
393
+ </div>
394
+ <div
395
+ style={{"marginTop": "2rem"}}
396
+ >
397
+ <h3>
398
+ Backend Walkers
399
+ </h3>
400
+ <p>
401
+ Basic example walkers:
402
+ {" "}
403
+ <code>
404
+ ping_server
405
+ </code>
406
+ {" "}
407
+ and
408
+ {" "}
409
+ <code>
410
+ get_server_message
411
+ </code>
412
+ </p>
413
+ <button
414
+ onClick={lambda e: any -> None{ handlePing();} }
415
+ style={{
416
+ "padding": "0.5rem 1.2rem",
417
+ "marginRight": "0.75rem",
418
+ "backgroundColor": "#3b82f6",
419
+ "color": "white",
420
+ "border": "none",
421
+ "borderRadius": "6px",
422
+ "cursor": "pointer"
423
+ }}
424
+ >
425
+ Ping Backend
426
+ </button>
427
+ <button
428
+ onClick={lambda e: any -> None{ handleCreateSampleTodo();} }
429
+ style={{
430
+ "padding": "0.5rem 1.2rem",
431
+ "backgroundColor": "#10b981",
432
+ "color": "white",
433
+ "border": "none",
434
+ "borderRadius": "6px",
435
+ "cursor": "pointer"
436
+ }}
437
+ >
438
+ Create Sample Todo
439
+ </button>
440
+ {pingResult
441
+ and (
442
+ <span
443
+ style={{"marginLeft": "0.5rem", "color": "#374151"}}
444
+ >
445
+ Result:
446
+ {" "}
447
+ <code>
448
+ {pingResult}
449
+ </code>
450
+ </span>
451
+ )}
452
+ {serverMessage
453
+ and (
454
+ <p
455
+ style={{"marginTop": "0.75rem", "color": "#374151"}}
456
+ >
457
+ Message:
458
+ {" "}
459
+ <code>
460
+ {serverMessage}
461
+ </code>
462
+ </p>
463
+ )}
464
+ {lastTodoMessage
465
+ and (
466
+ <p
467
+ style={{"marginTop": "0.5rem", "color": "#111827"}}
468
+ >
469
+ {lastTodoMessage}
470
+ </p>
471
+ )}
472
+ </div>
473
+ <div
474
+ style={{"marginTop": "2rem"}}
475
+ >
476
+ <h3>
477
+ Web Worker
478
+ </h3>
479
+ <p>
480
+ This demonstrates how to communicate with a
481
+ {" "}
482
+ <strong>Python backend worker</strong>
483
+ {" "}
484
+ using Web Workers for asynchronous processing.
485
+ </p>
486
+ <p
487
+ style={{"fontSize": "0.9rem", "color": "#666", "marginTop": "0.5rem"}}
488
+ >
489
+ File:
490
+ {" "}
491
+ <code>
492
+ worker.py
493
+ </code>
494
+ {" "}
495
+ — Runs in a separate thread to avoid blocking the UI.
496
+ </p>
497
+ <button
498
+ onClick={lambda -> None { handleClick(); }}
499
+ style={{
500
+ "padding": "0.5rem 1.2rem",
501
+ "marginRight": "0.75rem",
502
+ "backgroundColor": "#d73bf6ff",
503
+ "color": "white",
504
+ "border": "none",
505
+ "borderRadius": "6px",
506
+ "cursor": "pointer"
507
+ }}
508
+ >
509
+ Call Python Worker
510
+ </button>
511
+ {message && (
512
+ <p style={{ marginTop: "1rem", fontWeight: "bold" }}>
513
+ {message}
514
+ </p>
515
+ )}
516
+ </div>
517
+ </div>;
518
+ }
519
+
520
+ def:pub app -> any {
521
+ return <Router>
522
+ <div
523
+ style={{"fontFamily": "system-ui, -apple-system, sans-serif"}}
524
+ >
525
+ <Navigation />
526
+ <div
527
+ style={{
528
+ "maxWidth": "960px",
529
+ "margin": "0 auto",
530
+ "padding": "0 1rem 3rem 1rem"
531
+ }}
532
+ >
533
+ <Routes>
534
+ <Route
535
+ path="/"
536
+ element={<HomePage />}
537
+ />
538
+ <Route
539
+ path="/login"
540
+ element={<LoginPage />}
541
+ />
542
+ <Route
543
+ path="/signup"
544
+ element={<SignupPage />}
545
+ />
546
+ <Route
547
+ path="/nested"
548
+ element={<NestedImportsDemo />}
549
+ />
550
+ <Route
551
+ path="/features-test"
552
+ element={<FeaturesTest />}
553
+ />
554
+ <Route
555
+ path="/landing"
556
+ element={<LandingPage />}
557
+ />
558
+ <Route
559
+ path="/budget-planner"
560
+ element={<BudgetProvider>
561
+ <BudgetPlanner />
562
+ </BudgetProvider>}
563
+ />
564
+ <Route
565
+ path="*"
566
+ element={<NotFound />}
567
+ />
568
+ </Routes>
569
+ </div>
570
+ </div>
571
+ </Router>;
572
+ }
573
+ }