jac-client 0.2.9__tar.gz → 0.2.11__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 (168) hide show
  1. {jac_client-0.2.9 → jac_client-0.2.11}/PKG-INFO +5 -5
  2. {jac_client-0.2.9 → jac_client-0.2.11}/README.md +3 -3
  3. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/examples/all-in-one/button.jac +4 -3
  4. jac_client-0.2.11/jac_client/examples/all-in-one/components/CategoryFilter.jac +47 -0
  5. jac_client-0.2.11/jac_client/examples/all-in-one/components/Header.jac +17 -0
  6. jac_client-0.2.11/jac_client/examples/all-in-one/components/ProfitOverview.jac +64 -0
  7. jac_client-0.2.11/jac_client/examples/all-in-one/components/Summary.jac +76 -0
  8. jac_client-0.2.11/jac_client/examples/all-in-one/components/TransactionForm.jac +188 -0
  9. jac_client-0.2.11/jac_client/examples/all-in-one/components/TransactionItem.jac +62 -0
  10. jac_client-0.2.11/jac_client/examples/all-in-one/components/TransactionList.jac +44 -0
  11. jac_client-0.2.11/jac_client/examples/all-in-one/components/button.jac +8 -0
  12. jac_client-0.2.11/jac_client/examples/all-in-one/components/navigation.jac +126 -0
  13. jac_client-0.2.11/jac_client/examples/all-in-one/constants/categories.jac +36 -0
  14. jac_client-0.2.11/jac_client/examples/all-in-one/constants/clients.jac +12 -0
  15. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/examples/all-in-one/context/BudgetContext.jac +9 -6
  16. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/examples/all-in-one/hooks/useBudget.jac +18 -12
  17. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/examples/all-in-one/hooks/useLocalStorage.jac +14 -13
  18. jac_client-0.2.11/jac_client/examples/all-in-one/main.jac +542 -0
  19. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/examples/all-in-one/pages/BudgetPlanner.jac +19 -12
  20. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/examples/all-in-one/pages/FeaturesTest.jac +31 -15
  21. jac_client-0.2.11/jac_client/examples/all-in-one/pages/LandingPage.jac +124 -0
  22. jac_client-0.2.11/jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +65 -0
  23. jac_client-0.2.11/jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +675 -0
  24. jac_client-0.2.11/jac_client/examples/all-in-one/pages/loginPage.jac +127 -0
  25. jac_client-0.2.11/jac_client/examples/all-in-one/pages/nestedDemo.jac +54 -0
  26. jac_client-0.2.11/jac_client/examples/all-in-one/pages/notFound.jac +18 -0
  27. jac_client-0.2.11/jac_client/examples/all-in-one/pages/signupPage.jac +127 -0
  28. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/examples/all-in-one/utils/formatters.jac +5 -8
  29. jac_client-0.2.11/jac_client/examples/asset-serving/css-with-image/main.jac +92 -0
  30. jac_client-0.2.11/jac_client/examples/asset-serving/image-asset/main.jac +56 -0
  31. jac_client-0.2.11/jac_client/examples/asset-serving/import-alias/main.jac +109 -0
  32. jac_client-0.2.11/jac_client/examples/basic/main.jac +23 -0
  33. jac_client-0.2.11/jac_client/examples/basic-auth/main.jac +363 -0
  34. jac_client-0.2.11/jac_client/examples/basic-auth-with-router/main.jac +451 -0
  35. jac_client-0.2.11/jac_client/examples/basic-full-stack/main.jac +362 -0
  36. jac_client-0.2.11/jac_client/examples/css-styling/js-styling/main.jac +63 -0
  37. jac_client-0.2.11/jac_client/examples/css-styling/material-ui/main.jac +122 -0
  38. jac_client-0.2.11/jac_client/examples/css-styling/pure-css/main.jac +55 -0
  39. jac_client-0.2.11/jac_client/examples/css-styling/sass-example/main.jac +55 -0
  40. jac_client-0.2.11/jac_client/examples/css-styling/styled-components/main.jac +62 -0
  41. jac_client-0.2.11/jac_client/examples/css-styling/tailwind-example/main.jac +74 -0
  42. jac_client-0.2.11/jac_client/examples/full-stack-with-auth/main.jac +696 -0
  43. jac_client-0.2.11/jac_client/examples/little-x/main.jac +681 -0
  44. jac_client-0.2.11/jac_client/examples/little-x/src/submit-button.jac +17 -0
  45. jac_client-0.2.11/jac_client/examples/nested-folders/nested-advance/main.jac +26 -0
  46. jac_client-0.2.11/jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +9 -0
  47. jac_client-0.2.11/jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +15 -0
  48. jac_client-0.2.11/jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +40 -0
  49. jac_client-0.2.11/jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +19 -0
  50. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/examples/nested-folders/nested-basic/main.jac +7 -5
  51. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/examples/nested-folders/nested-basic/src/button.jac +4 -3
  52. jac_client-0.2.11/jac_client/examples/nested-folders/nested-basic/src/components/button.jac +8 -0
  53. jac_client-0.2.11/jac_client/examples/ts-support/main.jac +35 -0
  54. jac_client-0.2.11/jac_client/examples/with-router/main.jac +286 -0
  55. jac_client-0.2.11/jac_client/plugin/cli.jac +584 -0
  56. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/client_runtime.cl.jac +5 -3
  57. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/impl/client_runtime.impl.jac +1 -1
  58. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/plugin_config.jac +53 -99
  59. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/__init__.jac +0 -2
  60. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/compiler.jac +0 -1
  61. jac_client-0.2.11/jac_client/plugin/src/desktop_config.jac +31 -0
  62. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/impl/compiler.impl.jac +49 -17
  63. jac_client-0.2.11/jac_client/plugin/src/impl/desktop_config.impl.jac +191 -0
  64. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/impl/jac_to_js.impl.jac +5 -1
  65. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/impl/package_installer.impl.jac +20 -20
  66. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/impl/vite_bundler.impl.jac +121 -75
  67. jac_client-0.2.11/jac_client/plugin/src/targets/desktop/sidecar/main.py +144 -0
  68. jac_client-0.2.11/jac_client/plugin/src/targets/desktop_target.jac +37 -0
  69. jac_client-0.2.11/jac_client/plugin/src/targets/impl/desktop_target.impl.jac +2347 -0
  70. jac_client-0.2.11/jac_client/plugin/src/targets/impl/registry.impl.jac +64 -0
  71. jac_client-0.2.11/jac_client/plugin/src/targets/impl/web_target.impl.jac +157 -0
  72. jac_client-0.2.11/jac_client/plugin/src/targets/register.jac +21 -0
  73. jac_client-0.2.11/jac_client/plugin/src/targets/registry.jac +87 -0
  74. jac_client-0.2.11/jac_client/plugin/src/targets/web_target.jac +35 -0
  75. jac_client-0.2.11/jac_client/plugin/utils/__init__.jac +3 -0
  76. jac_client-0.2.11/jac_client/plugin/utils/bun_installer.jac +16 -0
  77. jac_client-0.2.11/jac_client/plugin/utils/impl/bun_installer.impl.jac +99 -0
  78. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/templates/fullstack.jacpack +1 -1
  79. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/conftest.py +56 -41
  80. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/fixtures/spawn_test/app.jac +49 -52
  81. jac_client-0.2.11/jac_client/tests/fixtures/with-ts/app.jac +35 -0
  82. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/test_cli.py +3 -6
  83. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/test_helpers.py +11 -18
  84. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/test_it.py +1 -1
  85. jac_client-0.2.11/jac_client/tests/test_it_desktop.py +891 -0
  86. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client.egg-info/PKG-INFO +5 -5
  87. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client.egg-info/SOURCES.txt +13 -4
  88. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client.egg-info/requires.txt +1 -1
  89. {jac_client-0.2.9 → jac_client-0.2.11}/pyproject.toml +2 -2
  90. jac_client-0.2.9/jac_client/examples/all-in-one/components/CategoryFilter.jac +0 -35
  91. jac_client-0.2.9/jac_client/examples/all-in-one/components/Header.jac +0 -13
  92. jac_client-0.2.9/jac_client/examples/all-in-one/components/ProfitOverview.jac +0 -50
  93. jac_client-0.2.9/jac_client/examples/all-in-one/components/Summary.jac +0 -53
  94. jac_client-0.2.9/jac_client/examples/all-in-one/components/TransactionForm.jac +0 -158
  95. jac_client-0.2.9/jac_client/examples/all-in-one/components/TransactionItem.jac +0 -55
  96. jac_client-0.2.9/jac_client/examples/all-in-one/components/TransactionList.jac +0 -37
  97. jac_client-0.2.9/jac_client/examples/all-in-one/components/button.jac +0 -7
  98. jac_client-0.2.9/jac_client/examples/all-in-one/components/navigation.jac +0 -132
  99. jac_client-0.2.9/jac_client/examples/all-in-one/constants/categories.jac +0 -37
  100. jac_client-0.2.9/jac_client/examples/all-in-one/constants/clients.jac +0 -13
  101. jac_client-0.2.9/jac_client/examples/all-in-one/main.jac +0 -573
  102. jac_client-0.2.9/jac_client/examples/all-in-one/pages/LandingPage.jac +0 -101
  103. jac_client-0.2.9/jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +0 -70
  104. jac_client-0.2.9/jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +0 -563
  105. jac_client-0.2.9/jac_client/examples/all-in-one/pages/loginPage.jac +0 -132
  106. jac_client-0.2.9/jac_client/examples/all-in-one/pages/nestedDemo.jac +0 -61
  107. jac_client-0.2.9/jac_client/examples/all-in-one/pages/notFound.jac +0 -19
  108. jac_client-0.2.9/jac_client/examples/all-in-one/pages/signupPage.jac +0 -133
  109. jac_client-0.2.9/jac_client/examples/asset-serving/css-with-image/main.jac +0 -88
  110. jac_client-0.2.9/jac_client/examples/asset-serving/image-asset/main.jac +0 -55
  111. jac_client-0.2.9/jac_client/examples/asset-serving/import-alias/main.jac +0 -111
  112. jac_client-0.2.9/jac_client/examples/basic/main.jac +0 -21
  113. jac_client-0.2.9/jac_client/examples/basic-auth/main.jac +0 -371
  114. jac_client-0.2.9/jac_client/examples/basic-auth-with-router/main.jac +0 -464
  115. jac_client-0.2.9/jac_client/examples/basic-full-stack/main.jac +0 -359
  116. jac_client-0.2.9/jac_client/examples/css-styling/js-styling/main.jac +0 -84
  117. jac_client-0.2.9/jac_client/examples/css-styling/material-ui/main.jac +0 -122
  118. jac_client-0.2.9/jac_client/examples/css-styling/pure-css/main.jac +0 -64
  119. jac_client-0.2.9/jac_client/examples/css-styling/sass-example/main.jac +0 -64
  120. jac_client-0.2.9/jac_client/examples/css-styling/styled-components/main.jac +0 -71
  121. jac_client-0.2.9/jac_client/examples/css-styling/tailwind-example/main.jac +0 -63
  122. jac_client-0.2.9/jac_client/examples/full-stack-with-auth/main.jac +0 -722
  123. jac_client-0.2.9/jac_client/examples/little-x/main.jac +0 -719
  124. jac_client-0.2.9/jac_client/examples/little-x/src/submit-button.jac +0 -16
  125. jac_client-0.2.9/jac_client/examples/nested-folders/nested-advance/main.jac +0 -35
  126. jac_client-0.2.9/jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +0 -11
  127. jac_client-0.2.9/jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +0 -19
  128. jac_client-0.2.9/jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +0 -43
  129. jac_client-0.2.9/jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +0 -25
  130. jac_client-0.2.9/jac_client/examples/nested-folders/nested-basic/src/components/button.jac +0 -7
  131. jac_client-0.2.9/jac_client/examples/ts-support/main.jac +0 -35
  132. jac_client-0.2.9/jac_client/examples/with-router/main.jac +0 -323
  133. jac_client-0.2.9/jac_client/plugin/cli.jac +0 -231
  134. jac_client-0.2.9/jac_client/plugin/src/babel_processor.jac +0 -18
  135. jac_client-0.2.9/jac_client/plugin/src/impl/babel_processor.impl.jac +0 -89
  136. jac_client-0.2.9/jac_client/plugin/utils/__init__.jac +0 -1
  137. jac_client-0.2.9/jac_client/plugin/utils/impl/node_installer.impl.jac +0 -249
  138. jac_client-0.2.9/jac_client/plugin/utils/node_installer.jac +0 -41
  139. jac_client-0.2.9/jac_client/tests/fixtures/with-ts/app.jac +0 -35
  140. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/examples/all-in-one/assets/workers/worker.py +0 -0
  141. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/client.jac +0 -0
  142. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/impl/client.impl.jac +0 -0
  143. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/impl/vite_client_bundle.impl.jac +0 -0
  144. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/asset_processor.jac +0 -0
  145. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/config_loader.jac +0 -0
  146. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/impl/asset_processor.impl.jac +0 -0
  147. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/impl/config_loader.impl.jac +0 -0
  148. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/impl/import_processor.impl.jac +0 -0
  149. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/import_processor.jac +0 -0
  150. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/jac_to_js.jac +0 -0
  151. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/package_installer.jac +0 -0
  152. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/src/vite_bundler.jac +0 -0
  153. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/plugin/vite_client_bundle.jac +0 -0
  154. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/templates/client.jacpack +0 -0
  155. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/__init__.py +0 -0
  156. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/fixtures/basic-app/app.jac +0 -0
  157. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/fixtures/cl_file/app.cl.jac +0 -0
  158. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/fixtures/cl_file/app.jac +0 -0
  159. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/fixtures/client_app_with_antd/app.jac +0 -0
  160. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/fixtures/js_import/app.jac +0 -0
  161. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/fixtures/relative_import/app.jac +0 -0
  162. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/fixtures/relative_import/button.jac +0 -0
  163. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/fixtures/test_fragments_spread/app.jac +0 -0
  164. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client/tests/test_e2e.py +0 -0
  165. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client.egg-info/dependency_links.txt +0 -0
  166. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client.egg-info/entry_points.txt +0 -0
  167. {jac_client-0.2.9 → jac_client-0.2.11}/jac_client.egg-info/top_level.txt +0 -0
  168. {jac_client-0.2.9 → jac_client-0.2.11}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jac-client
3
- Version: 0.2.9
3
+ Version: 0.2.11
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.9
14
+ Requires-Dist: jaclang>=0.9.11
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"
@@ -56,7 +56,7 @@ Visit `http://localhost:8000` to see your app! (The `app` component is served at
56
56
 
57
57
  You can also access the app at `http://localhost:8000/cl/app`.
58
58
 
59
- > **Note**: The `--npm` flag creates a client-side project with an organized folder structure. Without `--npm`, `jac create` creates a standard Jac project.
59
+ > **Note**: The `--use client` flag creates a client-side project with an organized folder structure. Without it, `jac create` creates a standard Jac project.
60
60
 
61
61
  ---
62
62
 
@@ -113,7 +113,7 @@ cl {
113
113
  ```jac
114
114
  # useState is auto-injected, only import useEffect
115
115
  cl import from react { useEffect }
116
- cl import from '@jac-client/utils' { jacSpawn }
116
+ cl import from '@jac/runtime' { jacSpawn }
117
117
 
118
118
  # Backend: Jac nodes and walkers
119
119
  node Todo {
@@ -164,7 +164,7 @@ cl {
164
164
  ## Requirements
165
165
 
166
166
  - Python: 3.12+
167
- - Node.js: For npm and Vite
167
+ - Bun: For package management and Vite bundling ([install](https://bun.sh))
168
168
  - Jac Language: `jaclang` (installed automatically)
169
169
 
170
170
  ---
@@ -38,7 +38,7 @@ Visit `http://localhost:8000` to see your app! (The `app` component is served at
38
38
 
39
39
  You can also access the app at `http://localhost:8000/cl/app`.
40
40
 
41
- > **Note**: The `--npm` flag creates a client-side project with an organized folder structure. Without `--npm`, `jac create` creates a standard Jac project.
41
+ > **Note**: The `--use client` flag creates a client-side project with an organized folder structure. Without it, `jac create` creates a standard Jac project.
42
42
 
43
43
  ---
44
44
 
@@ -95,7 +95,7 @@ cl {
95
95
  ```jac
96
96
  # useState is auto-injected, only import useEffect
97
97
  cl import from react { useEffect }
98
- cl import from '@jac-client/utils' { jacSpawn }
98
+ cl import from '@jac/runtime' { jacSpawn }
99
99
 
100
100
  # Backend: Jac nodes and walkers
101
101
  node Todo {
@@ -146,7 +146,7 @@ cl {
146
146
  ## Requirements
147
147
 
148
148
  - Python: 3.12+
149
- - Node.js: For npm and Vite
149
+ - Bun: For package management and Vite bundling ([install](https://bun.sh))
150
150
  - Jac Language: `jaclang` (installed automatically)
151
151
 
152
152
  ---
@@ -1,7 +1,8 @@
1
1
  cl import from antd { Button }
2
2
 
3
3
  cl def:pub CustomButtonRoot -> any {
4
- return <Button>
5
- Root Button
6
- </Button>;
4
+ return
5
+ <Button>
6
+ Root Button
7
+ </Button>;
7
8
  }
@@ -0,0 +1,47 @@
1
+ # Category filter component
2
+ # Demonstrates: iteration with map, conditional classes, events
3
+ cl import from ..constants.categories {
4
+ CATEGORIES,
5
+ CATEGORY_LABELS,
6
+ CATEGORY_COLORS
7
+ }
8
+
9
+ cl {
10
+ # Filter buttons for categories
11
+ def:pub CategoryFilter(selectedCategory: str, onSelect: any) -> any {
12
+ # Add "ALL" to the beginning of categories
13
+ allCategories = ["ALL"].concat(CATEGORIES);
14
+
15
+ return
16
+ <div className="category-filter">
17
+ <h3 className="filter-title">
18
+ Filter by Category
19
+ </h3>
20
+ <div className="filter-buttons">
21
+ {allCategories.map(
22
+ lambda cat: str -> any { isActive = selectedCategory == cat;color = CATEGORY_COLORS[
23
+ cat
24
+ ]
25
+ if cat != "ALL"
26
+ else "#374151";return
27
+ <button
28
+ key={cat}
29
+ className={("filter-btn active")
30
+ if isActive
31
+ else ("filter-btn")}
32
+ style={{
33
+ "borderColor": color,
34
+ "backgroundColor": (color)
35
+ if isActive
36
+ else ("transparent"),
37
+ "color": ("#fff") if isActive else (color)
38
+ }}
39
+ onClick={lambda : onSelect(cat)}
40
+ >
41
+ {(cat) if cat == "ALL" else (CATEGORY_LABELS[cat])}
42
+ </button>; }
43
+ )}
44
+ </div>
45
+ </div>;
46
+ }
47
+ }
@@ -0,0 +1,17 @@
1
+ # Header component
2
+ # Demonstrates: simple component, CSS classes
3
+ cl {
4
+ def:pub Header -> any {
5
+ return
6
+ <header className="header">
7
+ <div className="header-content">
8
+ <h1 className="header-title">
9
+ Budget Planner
10
+ </h1>
11
+ <p className="header-subtitle">
12
+ Track your income and expenses
13
+ </p>
14
+ </div>
15
+ </header>;
16
+ }
17
+ }
@@ -0,0 +1,64 @@
1
+ # Profit Overview component - monthly profit snapshot
2
+ # Demonstrates: context usage, calculated displays, formatting
3
+ cl import from ..context.BudgetContext {
4
+ useBudgetContext
5
+ }
6
+ cl import from ..utils.formatters { formatCurrency }
7
+
8
+ cl {
9
+ def:pub ProfitOverview -> any {
10
+ budget = useBudgetContext();
11
+
12
+ businessIncome = budget["businessIncome"];
13
+ businessExpenses = budget["businessExpenses"];
14
+ taxReserve = budget["taxReserve"];
15
+ netProfit = budget["netProfit"];
16
+
17
+ return
18
+ <div className="profit-overview">
19
+ <h3 className="profit-title">
20
+ Monthly Profit Snapshot
21
+ </h3>
22
+ <div className="profit-breakdown">
23
+ <div className="profit-row income">
24
+ <span className="profit-label">
25
+ Business Income
26
+ </span>
27
+ <span className="profit-value positive">
28
+ +{formatCurrency(businessIncome)}
29
+ </span>
30
+ </div>
31
+ <div className="profit-row expense">
32
+ <span className="profit-label">
33
+ Business Expenses
34
+ </span>
35
+ <span className="profit-value negative">
36
+ -{formatCurrency(businessExpenses)}
37
+ </span>
38
+ </div>
39
+ <div className="profit-row tax">
40
+ <span className="profit-label">
41
+ Tax Reserve (20%)
42
+ </span>
43
+ <span className="profit-value negative">
44
+ -{formatCurrency(taxReserve)}
45
+ </span>
46
+ </div>
47
+ <div className="profit-row total">
48
+ <span className="profit-label">
49
+ Net Profit
50
+ </span>
51
+ <span
52
+ className={("profit-value bold positive")
53
+ if netProfit >= 0
54
+ else ("profit-value bold negative")}
55
+ >
56
+ {("+") if netProfit > 0 else ("")}{formatCurrency(
57
+ netProfit
58
+ )}
59
+ </span>
60
+ </div>
61
+ </div>
62
+ </div>;
63
+ }
64
+ }
@@ -0,0 +1,76 @@
1
+ # Summary component - displays budget totals with business/personal breakdown
2
+ # Demonstrates: context usage, conditional rendering, ternary operator, 6-card layout
3
+ cl import from ..context.BudgetContext {
4
+ useBudgetContext
5
+ }
6
+ cl import from ..utils.formatters { formatCurrency }
7
+
8
+ cl {
9
+ def:pub Summary -> any {
10
+ budget = useBudgetContext();
11
+
12
+ # Business/Personal breakdown
13
+ businessIncome = budget["businessIncome"];
14
+ businessExpenses = budget["businessExpenses"];
15
+ personalIncome = budget["personalIncome"];
16
+ personalExpenses = budget["personalExpenses"];
17
+ taxReserve = budget["taxReserve"];
18
+ netProfit = budget["netProfit"];
19
+
20
+ return
21
+ <div className="summary">
22
+ <div className="summary-card business-income">
23
+ <span className="summary-label">
24
+ Business Income
25
+ </span>
26
+ <span className="summary-value">
27
+ {formatCurrency(businessIncome)}
28
+ </span>
29
+ </div>
30
+ <div className="summary-card business-expenses">
31
+ <span className="summary-label">
32
+ Business Expenses
33
+ </span>
34
+ <span className="summary-value">
35
+ {formatCurrency(businessExpenses)}
36
+ </span>
37
+ </div>
38
+ <div className="summary-card personal-income">
39
+ <span className="summary-label">
40
+ Personal Income
41
+ </span>
42
+ <span className="summary-value">
43
+ {formatCurrency(personalIncome)}
44
+ </span>
45
+ </div>
46
+ <div className="summary-card personal-expenses">
47
+ <span className="summary-label">
48
+ Personal Expenses
49
+ </span>
50
+ <span className="summary-value">
51
+ {formatCurrency(personalExpenses)}
52
+ </span>
53
+ </div>
54
+ <div className="summary-card tax-reserve">
55
+ <span className="summary-label">
56
+ Tax Reserve (20%)
57
+ </span>
58
+ <span className="summary-value">
59
+ {formatCurrency(taxReserve)}
60
+ </span>
61
+ </div>
62
+ <div
63
+ className={("summary-card net-profit positive")
64
+ if netProfit >= 0
65
+ else ("summary-card net-profit negative")}
66
+ >
67
+ <span className="summary-label">
68
+ Net Profit
69
+ </span>
70
+ <span className="summary-value">
71
+ {("+") if netProfit > 0 else ("")}{formatCurrency(netProfit)}
72
+ </span>
73
+ </div>
74
+ </div>;
75
+ }
76
+ }
@@ -0,0 +1,188 @@
1
+ # Transaction form component
2
+ # Demonstrates: form handling, useState, events, select options
3
+ cl import from ..context.BudgetContext {
4
+ useBudgetContext
5
+ }
6
+ cl import from ..constants.categories { CATEGORIES, CATEGORY_LABELS }
7
+ cl import from ..constants.clients { CLIENTS }
8
+
9
+ cl {
10
+ def:pub TransactionForm -> any {
11
+ [description, setDescription] = useState("");
12
+ [amount, setAmount] = useState("");
13
+ [category, setCategory] = useState("OTHER");
14
+ [txType, setTxType] = useState("expense");
15
+ [isBusiness, setIsBusiness] = useState(false);
16
+ [clientName, setClientName] = useState("");
17
+ budget = useBudgetContext();
18
+
19
+ def handleSubmit(e: any) -> None {
20
+ e.preventDefault();
21
+
22
+ # Validate inputs
23
+ trimmedDesc = description.trim();
24
+ if trimmedDesc == "" or amount == "" {
25
+ return;
26
+ }
27
+
28
+ parsedAmount = parseFloat(amount);
29
+ if isNaN(parsedAmount) or parsedAmount <= 0 {
30
+ return;
31
+ }
32
+
33
+ # Add the transaction
34
+ budget["addTransaction"](
35
+ trimmedDesc, parsedAmount, category, txType, isBusiness, clientName
36
+ );
37
+
38
+ # Reset form
39
+ setDescription("");
40
+ setAmount("");
41
+ setCategory("OTHER");
42
+ setIsBusiness(false);
43
+ setClientName("");
44
+ }
45
+
46
+ # Filter categories based on type (income only has INCOME category)
47
+ availableCategories = CATEGORIES.filter(
48
+ lambda cat: str -> bool { if txType == "income" {
49
+ return cat == "INCOME";
50
+ }return cat != "INCOME"; }
51
+ );
52
+
53
+ # Show client dropdown only for business income
54
+ showClientDropdown = txType == "income" and isBusiness;
55
+
56
+ return
57
+ <form className="transaction-form" onSubmit={handleSubmit}>
58
+ <div className="form-row">
59
+ <div className="form-group type-toggle">
60
+ <button
61
+ type="button"
62
+ className={("toggle-btn active")
63
+ if txType == "expense"
64
+ else ("toggle-btn")}
65
+ onClick={lambda : setTxType("expense")}
66
+ >
67
+ Expense
68
+ </button>
69
+ <button
70
+ type="button"
71
+ className={("toggle-btn active income")
72
+ if txType == "income"
73
+ else ("toggle-btn")}
74
+ onClick={lambda : setTxType("income")}
75
+ >
76
+ Income
77
+ </button>
78
+ </div>
79
+ <div className="form-group business-toggle">
80
+ <button
81
+ type="button"
82
+ className={("toggle-btn active")
83
+ if isBusiness
84
+ else ("toggle-btn")}
85
+ onClick={lambda : setIsBusiness(true)}
86
+ >
87
+ Business
88
+ </button>
89
+ <button
90
+ type="button"
91
+ className={("toggle-btn active")
92
+ if not isBusiness
93
+ else ("toggle-btn")}
94
+ onClick={lambda : setIsBusiness(false)}
95
+ >
96
+ Personal
97
+ </button>
98
+ </div>
99
+ </div>
100
+ <div className="form-row">
101
+ <div className="form-group">
102
+ <label htmlFor="description">
103
+ Description
104
+ </label>
105
+ <input
106
+ id="description"
107
+ type="text"
108
+ value={description}
109
+ onChange={lambda e: any -> None { setDescription(
110
+ e.target.value
111
+ );}}
112
+ placeholder="Enter description..."
113
+ className="form-input"
114
+ />
115
+ </div>
116
+ <div className="form-group">
117
+ <label htmlFor="amount">
118
+ Amount
119
+ </label>
120
+ <input
121
+ id="amount"
122
+ type="number"
123
+ value={amount}
124
+ onChange={lambda e: any -> None { setAmount(
125
+ e.target.value
126
+ );}}
127
+ placeholder="0.00"
128
+ min="0"
129
+ step="0.01"
130
+ className="form-input"
131
+ />
132
+ </div>
133
+ <div className="form-group">
134
+ <label htmlFor="category">
135
+ Category
136
+ </label>
137
+ <select
138
+ id="category"
139
+ value={category}
140
+ onChange={lambda e: any -> None { setCategory(
141
+ e.target.value
142
+ );}}
143
+ className="form-select"
144
+ >
145
+ {availableCategories.map(
146
+ lambda cat: str -> any { return
147
+ <option key={cat} value={cat}>
148
+ {CATEGORY_LABELS[cat]}
149
+ </option>; }
150
+ )}
151
+ </select>
152
+ </div>
153
+ {showClientDropdown
154
+ and <div className="form-group">
155
+ <label htmlFor="client">
156
+ Client
157
+ </label>
158
+ <select
159
+ id="client"
160
+ value={clientName}
161
+ onChange={lambda e: any -> None { setClientName(
162
+ e.target.value
163
+ );}}
164
+ className="form-select"
165
+ >
166
+ <option value="">
167
+ Select Client (Optional)
168
+ </option>
169
+ {CLIENTS.map(
170
+ lambda client: str -> any { return
171
+ <option key={client} value={client}>
172
+ {client}
173
+ </option>; }
174
+ )}
175
+ </select>
176
+ </div>}
177
+ <div className="form-group">
178
+ <label>
179
+ Action
180
+ </label>
181
+ <button type="submit" className="submit-btn">
182
+ Add {(txType[0].toUpperCase() + txType.slice(1))}
183
+ </button>
184
+ </div>
185
+ </div>
186
+ </form>;
187
+ }
188
+ }
@@ -0,0 +1,62 @@
1
+ # Single transaction item component
2
+ # Demonstrates: NEW PROPS PATTERN (direct parameters, NOT props dict)
3
+ cl import from ..utils.formatters {
4
+ formatCurrency,
5
+ formatDate
6
+ }
7
+ cl import from ..constants.categories { CATEGORY_COLORS, CATEGORY_LABELS }
8
+
9
+ cl {
10
+ # NEW WAY: Direct parameters instead of props: dict
11
+ def:pub TransactionItem(
12
+ id: str,
13
+ description: str,
14
+ amount: float,
15
+ category: str,
16
+ txType: str,
17
+ date: str,
18
+ isBusiness: bool,
19
+ clientName: any,
20
+ onDelete: any
21
+ ) -> any {
22
+ isIncome = txType == "income";
23
+ color = CATEGORY_COLORS[category];
24
+ label = CATEGORY_LABELS[category];
25
+
26
+ return
27
+ <div className="transaction-item">
28
+ <div className="tx-left">
29
+ <span className="tx-category" style={{"backgroundColor": color}}>
30
+ {label}
31
+ </span>
32
+ <div className="tx-details">
33
+ <span className="tx-description">
34
+ {description}{(clientName != None and isIncome)
35
+ and <span className="tx-client">
36
+ • {clientName}
37
+ </span>}
38
+ </span>
39
+ <span className="tx-date">
40
+ {formatDate(date)}
41
+ </span>
42
+ </div>
43
+ </div>
44
+ <div className="tx-right">
45
+ <span
46
+ className={("tx-amount income")
47
+ if isIncome
48
+ else ("tx-amount expense")}
49
+ >
50
+ {("+") if isIncome else ("-")}{formatCurrency(amount)}
51
+ </span>
52
+ <button
53
+ className="delete-btn"
54
+ onClick={lambda : onDelete(id)}
55
+ title="Delete transaction"
56
+ >
57
+ X
58
+ </button>
59
+ </div>
60
+ </div>;
61
+ }
62
+ }
@@ -0,0 +1,44 @@
1
+ # Transaction list component
2
+ # Demonstrates: rendering lists with map, passing props to child components
3
+ cl import from .TransactionItem {
4
+ TransactionItem
5
+ }
6
+
7
+ cl {
8
+ # Props: transactions list and delete handler
9
+ def:pub TransactionList(transactions: list, onDelete: any) -> any {
10
+ if transactions.length == 0 {
11
+ return
12
+ <div className="empty-state">
13
+ <p>
14
+ No transactions yet.
15
+ </p>
16
+ <p>
17
+ Add your first income or expense above!
18
+ </p>
19
+ </div>;
20
+ }
21
+
22
+ return
23
+ <div className="transaction-list">
24
+ <h3 className="list-title">
25
+ Transactions ({transactions.length})
26
+ </h3>
27
+ {transactions.map(
28
+ lambda tx: dict -> any { return
29
+ <TransactionItem
30
+ key={tx["id"]}
31
+ id={tx["id"]}
32
+ description={tx["description"]}
33
+ amount={tx["amount"]}
34
+ category={tx["category"]}
35
+ txType={tx["type"]}
36
+ date={tx["date"]}
37
+ isBusiness={tx["isBusinessTransaction"] || false}
38
+ clientName={tx["clientName"] || None}
39
+ onDelete={onDelete}
40
+ />; }
41
+ )}
42
+ </div>;
43
+ }
44
+ }
@@ -0,0 +1,8 @@
1
+ cl import from antd { Button }
2
+
3
+ cl def:pub CustomButton -> any {
4
+ return
5
+ <Button>
6
+ Nested Button
7
+ </Button>;
8
+ }