@askrjs/cli 0.0.2

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 (460) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +140 -0
  3. package/dist/add-DqhqRzBQ.js +555 -0
  4. package/dist/add-DqhqRzBQ.js.map +1 -0
  5. package/dist/add.js +3 -0
  6. package/dist/cli.js +91 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/create.js +923 -0
  9. package/dist/create.js.map +1 -0
  10. package/dist/is-direct-execution-Cdlr-ZUl.js +20 -0
  11. package/dist/is-direct-execution-Cdlr-ZUl.js.map +1 -0
  12. package/dist/openapi.js +127 -0
  13. package/dist/openapi.js.map +1 -0
  14. package/dist/skills/askr-accessibility/SKILL.md +68 -0
  15. package/dist/skills/askr-accessibility/agents/openai.yaml +4 -0
  16. package/dist/skills/askr-agent-execution/SKILL.md +85 -0
  17. package/dist/skills/askr-agent-execution/agents/openai.yaml +4 -0
  18. package/dist/skills/askr-agent-workflows/SKILL.md +57 -0
  19. package/dist/skills/askr-agent-workflows/agents/openai.yaml +4 -0
  20. package/dist/skills/askr-api-integration/SKILL.md +79 -0
  21. package/dist/skills/askr-api-integration/agents/openai.yaml +4 -0
  22. package/dist/skills/askr-app-builder/SKILL.md +99 -0
  23. package/dist/skills/askr-app-builder/agents/openai.yaml +4 -0
  24. package/dist/skills/askr-auth-access/SKILL.md +74 -0
  25. package/dist/skills/askr-auth-access/agents/openai.yaml +4 -0
  26. package/dist/skills/askr-cli-vite/SKILL.md +76 -0
  27. package/dist/skills/askr-cli-vite/agents/openai.yaml +4 -0
  28. package/dist/skills/askr-dashboard-charts/SKILL.md +82 -0
  29. package/dist/skills/askr-dashboard-charts/agents/openai.yaml +4 -0
  30. package/dist/skills/askr-design-system/SKILL.md +86 -0
  31. package/dist/skills/askr-design-system/agents/openai.yaml +4 -0
  32. package/dist/skills/askr-env-config/SKILL.md +74 -0
  33. package/dist/skills/askr-env-config/agents/openai.yaml +4 -0
  34. package/dist/skills/askr-error-loading-empty/SKILL.md +89 -0
  35. package/dist/skills/askr-error-loading-empty/agents/openai.yaml +4 -0
  36. package/dist/skills/askr-file-upload-artifacts/SKILL.md +77 -0
  37. package/dist/skills/askr-file-upload-artifacts/agents/openai.yaml +4 -0
  38. package/dist/skills/askr-forms-tables-crud/SKILL.md +98 -0
  39. package/dist/skills/askr-forms-tables-crud/agents/openai.yaml +4 -0
  40. package/dist/skills/askr-mental-model/SKILL.md +109 -0
  41. package/dist/skills/askr-mental-model/agents/openai.yaml +4 -0
  42. package/dist/skills/askr-migration-react/SKILL.md +81 -0
  43. package/dist/skills/askr-migration-react/agents/openai.yaml +4 -0
  44. package/dist/skills/askr-observability-debugging/SKILL.md +83 -0
  45. package/dist/skills/askr-observability-debugging/agents/openai.yaml +4 -0
  46. package/dist/skills/askr-project-structure/SKILL.md +79 -0
  47. package/dist/skills/askr-project-structure/agents/openai.yaml +4 -0
  48. package/dist/skills/askr-query-mutation/SKILL.md +115 -0
  49. package/dist/skills/askr-query-mutation/agents/openai.yaml +4 -0
  50. package/dist/skills/askr-realtime-streaming/SKILL.md +76 -0
  51. package/dist/skills/askr-realtime-streaming/agents/openai.yaml +4 -0
  52. package/dist/skills/askr-resources-data/SKILL.md +100 -0
  53. package/dist/skills/askr-resources-data/agents/openai.yaml +4 -0
  54. package/dist/skills/askr-routing-layouts/SKILL.md +107 -0
  55. package/dist/skills/askr-routing-layouts/agents/openai.yaml +4 -0
  56. package/dist/skills/askr-runtime-reactivity/SKILL.md +92 -0
  57. package/dist/skills/askr-runtime-reactivity/agents/openai.yaml +4 -0
  58. package/dist/skills/askr-ssr-ssg/SKILL.md +76 -0
  59. package/dist/skills/askr-ssr-ssg/agents/openai.yaml +4 -0
  60. package/dist/skills/askr-testing-determinism/SKILL.md +75 -0
  61. package/dist/skills/askr-testing-determinism/agents/openai.yaml +4 -0
  62. package/dist/skills/askr-theming/SKILL.md +86 -0
  63. package/dist/skills/askr-theming/agents/openai.yaml +4 -0
  64. package/dist/skills/askr-ui-composition/SKILL.md +92 -0
  65. package/dist/skills/askr-ui-composition/agents/openai.yaml +4 -0
  66. package/dist/skills-Bh0mEhIx.js +682 -0
  67. package/dist/skills-Bh0mEhIx.js.map +1 -0
  68. package/dist/skills.js +3 -0
  69. package/dist/ssg.js +188 -0
  70. package/dist/ssg.js.map +1 -0
  71. package/dist/templates/full-stack/AGENTS.md +12 -0
  72. package/dist/templates/full-stack/README.md +18 -0
  73. package/dist/templates/full-stack/gitignore.template +4 -0
  74. package/dist/templates/full-stack/index.html +14 -0
  75. package/dist/templates/full-stack/package.json +37 -0
  76. package/dist/templates/full-stack/server.ts +13 -0
  77. package/dist/templates/full-stack/src/action-authorizations.ts +10 -0
  78. package/dist/templates/full-stack/src/actions/create-message.ts +10 -0
  79. package/dist/templates/full-stack/src/i18n.ts +8 -0
  80. package/dist/templates/full-stack/src/main.tsx +12 -0
  81. package/dist/templates/full-stack/src/pages/home.tsx +25 -0
  82. package/dist/templates/full-stack/src/pages/layout.tsx +33 -0
  83. package/dist/templates/full-stack/src/pages/not-found.tsx +4 -0
  84. package/dist/templates/full-stack/src/routes.tsx +20 -0
  85. package/dist/templates/full-stack/src/schemas.ts +11 -0
  86. package/dist/templates/full-stack/src/server/action-registry.ts +12 -0
  87. package/dist/templates/full-stack/src/server/actions/create-message.ts +14 -0
  88. package/dist/templates/full-stack/src/server/app.ts +66 -0
  89. package/dist/templates/full-stack/src/server/dependencies.ts +55 -0
  90. package/dist/templates/full-stack/src/server/entry-server.ts +8 -0
  91. package/dist/templates/full-stack/src/telemetry.ts +4 -0
  92. package/dist/templates/full-stack/src/vite-server.d.ts +6 -0
  93. package/dist/templates/full-stack/tests/actions/create-message.test.ts +13 -0
  94. package/dist/templates/full-stack/tsconfig.json +16 -0
  95. package/dist/templates/full-stack/vite.config.ts +11 -0
  96. package/dist/templates/spa/AGENTS.md +60 -0
  97. package/dist/templates/spa/README.md +96 -0
  98. package/dist/templates/spa/gitignore.template +16 -0
  99. package/dist/templates/spa/index.html +13 -0
  100. package/dist/templates/spa/package.json +35 -0
  101. package/dist/templates/spa/src/adapters/operations-client.ts +90 -0
  102. package/dist/templates/spa/src/components/shared/metric-card.tsx +27 -0
  103. package/dist/templates/spa/src/components/shared/status-badge.tsx +24 -0
  104. package/dist/templates/spa/src/features/operations/operations.query.ts +9 -0
  105. package/dist/templates/spa/src/main.tsx +10 -0
  106. package/dist/templates/spa/src/pages/_layout.tsx +9 -0
  107. package/dist/templates/spa/src/pages/_routes.tsx +27 -0
  108. package/dist/templates/spa/src/pages/app/_layout.tsx +94 -0
  109. package/dist/templates/spa/src/pages/app/_routes.tsx +10 -0
  110. package/dist/templates/spa/src/pages/app/admin-home.tsx +152 -0
  111. package/dist/templates/spa/src/pages/app/agent-runs.tsx +93 -0
  112. package/dist/templates/spa/src/pages/app/settings.tsx +91 -0
  113. package/dist/templates/spa/src/pages/auth/_layout.tsx +38 -0
  114. package/dist/templates/spa/src/pages/auth/_routes.tsx +6 -0
  115. package/dist/templates/spa/src/pages/auth/login.tsx +63 -0
  116. package/dist/templates/spa/src/pages/not-found.tsx +22 -0
  117. package/dist/templates/spa/src/pages/public/_layout.tsx +47 -0
  118. package/dist/templates/spa/src/pages/public/_routes.tsx +6 -0
  119. package/dist/templates/spa/src/pages/public/home.tsx +143 -0
  120. package/dist/templates/spa/src/shared/format.ts +12 -0
  121. package/dist/templates/spa/src/shared/navigation.ts +15 -0
  122. package/dist/templates/spa/src/styles/components.css +49 -0
  123. package/dist/templates/spa/src/styles/layout.css +192 -0
  124. package/dist/templates/spa/src/styles/reset.css +44 -0
  125. package/dist/templates/spa/src/styles/theme.css +57 -0
  126. package/dist/templates/spa/src/styles/tokens.css +20 -0
  127. package/dist/templates/spa/src/styles.css +7 -0
  128. package/dist/templates/spa/src/styles.d.ts +1 -0
  129. package/dist/templates/spa/tests/app.test.tsx +37 -0
  130. package/dist/templates/spa/tests/components/shared.test.tsx +12 -0
  131. package/dist/templates/spa/tests/resources.test.ts +22 -0
  132. package/dist/templates/spa/tsconfig.json +20 -0
  133. package/dist/templates/spa/tsconfig.node.json +10 -0
  134. package/dist/templates/spa/vite.config.ts +24 -0
  135. package/dist/templates/spa/vitest.config.ts +17 -0
  136. package/dist/templates/ssg/AGENTS.md +55 -0
  137. package/dist/templates/ssg/README.md +39 -0
  138. package/dist/templates/ssg/gitignore.template +17 -0
  139. package/dist/templates/ssg/index.html +13 -0
  140. package/dist/templates/ssg/package.json +35 -0
  141. package/dist/templates/ssg/src/app.tsx +14 -0
  142. package/dist/templates/ssg/src/components/badge.tsx +3 -0
  143. package/dist/templates/ssg/src/components/counter.tsx +30 -0
  144. package/dist/templates/ssg/src/components/site-shell.tsx +111 -0
  145. package/dist/templates/ssg/src/jsx.d.ts +23 -0
  146. package/dist/templates/ssg/src/main.tsx +8 -0
  147. package/dist/templates/ssg/src/pages/about.tsx +82 -0
  148. package/dist/templates/ssg/src/pages/content.tsx +63 -0
  149. package/dist/templates/ssg/src/pages/example.tsx +97 -0
  150. package/dist/templates/ssg/src/pages/home.tsx +51 -0
  151. package/dist/templates/ssg/src/resources/user.ts +15 -0
  152. package/dist/templates/ssg/src/routes.tsx +15 -0
  153. package/dist/templates/ssg/src/styles.css +89 -0
  154. package/dist/templates/ssg/src/vite-env.d.ts +5 -0
  155. package/dist/templates/ssg/ssg.config.ts +34 -0
  156. package/dist/templates/ssg/tests/app.test.tsx +19 -0
  157. package/dist/templates/ssg/tests/components/counter.test.tsx +18 -0
  158. package/dist/templates/ssg/tests/resources.test.ts +11 -0
  159. package/dist/templates/ssg/tests/ssg-config.test.ts +11 -0
  160. package/dist/templates/ssg/tsconfig.json +20 -0
  161. package/dist/templates/ssg/tsconfig.node.json +10 -0
  162. package/dist/templates/ssg/vite.config.ts +24 -0
  163. package/dist/templates/ssg/vitest.config.ts +17 -0
  164. package/dist/templates/ssr/AGENTS.md +28 -0
  165. package/dist/templates/ssr/README.md +38 -0
  166. package/dist/templates/ssr/gitignore.template +16 -0
  167. package/dist/templates/ssr/index.html +13 -0
  168. package/dist/templates/ssr/package.json +34 -0
  169. package/dist/templates/ssr/server.ts +16 -0
  170. package/dist/templates/ssr/src/app.tsx +21 -0
  171. package/dist/templates/ssr/src/components/counter.tsx +26 -0
  172. package/dist/templates/ssr/src/entry-server.tsx +10 -0
  173. package/dist/templates/ssr/src/main.tsx +11 -0
  174. package/dist/templates/ssr/src/pages/about.tsx +75 -0
  175. package/dist/templates/ssr/src/pages/example.tsx +113 -0
  176. package/dist/templates/ssr/src/pages/home.tsx +56 -0
  177. package/dist/templates/ssr/src/resources/user.ts +15 -0
  178. package/dist/templates/ssr/src/routes.tsx +13 -0
  179. package/dist/templates/ssr/src/styles.css +148 -0
  180. package/dist/templates/ssr/src/vite-server.d.ts +7 -0
  181. package/dist/templates/ssr/tests/app.test.tsx +24 -0
  182. package/dist/templates/ssr/tests/components/counter.test.tsx +13 -0
  183. package/dist/templates/ssr/tests/resources.test.ts +11 -0
  184. package/dist/templates/ssr/tsconfig.json +22 -0
  185. package/dist/templates/ssr/tsconfig.node.json +10 -0
  186. package/dist/templates/ssr/tsconfig.server.json +15 -0
  187. package/dist/templates/ssr/vite.config.ts +25 -0
  188. package/dist/templates/ssr/vitest.config.ts +13 -0
  189. package/dist/templates/startkit/AGENTS.md +77 -0
  190. package/dist/templates/startkit/README.md +192 -0
  191. package/dist/templates/startkit/gitignore.template +16 -0
  192. package/dist/templates/startkit/index.html +13 -0
  193. package/dist/templates/startkit/package.json +35 -0
  194. package/dist/templates/startkit/src/components/app-header.tsx +93 -0
  195. package/dist/templates/startkit/src/components/app-sidebar.tsx +95 -0
  196. package/dist/templates/startkit/src/components/data-table.tsx +80 -0
  197. package/dist/templates/startkit/src/components/empty-state.tsx +13 -0
  198. package/dist/templates/startkit/src/components/page-header.tsx +23 -0
  199. package/dist/templates/startkit/src/components/stat-card.tsx +24 -0
  200. package/dist/templates/startkit/src/features/accounts/account-filters.tsx +61 -0
  201. package/dist/templates/startkit/src/features/accounts/account-table.tsx +79 -0
  202. package/dist/templates/startkit/src/lib/format.ts +31 -0
  203. package/dist/templates/startkit/src/lib/mock-data.ts +441 -0
  204. package/dist/templates/startkit/src/lib/routes.ts +116 -0
  205. package/dist/templates/startkit/src/main.tsx +12 -0
  206. package/dist/templates/startkit/src/pages/_layout.tsx +56 -0
  207. package/dist/templates/startkit/src/pages/auth/_layout.tsx +7 -0
  208. package/dist/templates/startkit/src/pages/auth/login.tsx +129 -0
  209. package/dist/templates/startkit/src/pages/home.tsx +83 -0
  210. package/dist/templates/startkit/src/pages/not-found.tsx +24 -0
  211. package/dist/templates/startkit/src/pages/workspace/_layout.tsx +17 -0
  212. package/dist/templates/startkit/src/pages/workspace/accounts/index.tsx +217 -0
  213. package/dist/templates/startkit/src/pages/workspace/dashboard.tsx +118 -0
  214. package/dist/templates/startkit/src/pages/workspace/settings.tsx +218 -0
  215. package/dist/templates/startkit/src/router.tsx +7 -0
  216. package/dist/templates/startkit/src/routes/auth-config.ts +38 -0
  217. package/dist/templates/startkit/src/routes/auth.ts +8 -0
  218. package/dist/templates/startkit/src/routes/index.ts +28 -0
  219. package/dist/templates/startkit/src/routes/public.ts +8 -0
  220. package/dist/templates/startkit/src/routes/workspace/accounts.ts +8 -0
  221. package/dist/templates/startkit/src/routes/workspace/index.ts +14 -0
  222. package/dist/templates/startkit/src/styles/components.css +396 -0
  223. package/dist/templates/startkit/src/styles/layout.css +192 -0
  224. package/dist/templates/startkit/src/styles/reset.css +38 -0
  225. package/dist/templates/startkit/src/styles/theme.css +76 -0
  226. package/dist/templates/startkit/src/styles/tokens.css +67 -0
  227. package/dist/templates/startkit/src/styles.css +7 -0
  228. package/dist/templates/startkit/src/toast.ts +55 -0
  229. package/dist/templates/startkit/src/utils/join-classes.ts +4 -0
  230. package/dist/templates/startkit/src/vite-env.d.ts +5 -0
  231. package/dist/templates/startkit/tests/app.test.tsx +32 -0
  232. package/dist/templates/startkit/tests/preferences.test.ts +43 -0
  233. package/dist/templates/startkit/tests/resources.test.ts +82 -0
  234. package/dist/templates/startkit/tsconfig.json +20 -0
  235. package/dist/templates/startkit/tsconfig.node.json +10 -0
  236. package/dist/templates/startkit/vite.config.ts +32 -0
  237. package/dist/templates/startkit/vitest.config.ts +13 -0
  238. package/dist/update-DyW1na5V.js +1140 -0
  239. package/dist/update-DyW1na5V.js.map +1 -0
  240. package/dist/update.js +3 -0
  241. package/package.json +84 -0
  242. package/skills/askr-accessibility/SKILL.md +68 -0
  243. package/skills/askr-accessibility/agents/openai.yaml +4 -0
  244. package/skills/askr-agent-execution/SKILL.md +85 -0
  245. package/skills/askr-agent-execution/agents/openai.yaml +4 -0
  246. package/skills/askr-agent-workflows/SKILL.md +57 -0
  247. package/skills/askr-agent-workflows/agents/openai.yaml +4 -0
  248. package/skills/askr-api-integration/SKILL.md +79 -0
  249. package/skills/askr-api-integration/agents/openai.yaml +4 -0
  250. package/skills/askr-app-builder/SKILL.md +99 -0
  251. package/skills/askr-app-builder/agents/openai.yaml +4 -0
  252. package/skills/askr-auth-access/SKILL.md +74 -0
  253. package/skills/askr-auth-access/agents/openai.yaml +4 -0
  254. package/skills/askr-cli-vite/SKILL.md +76 -0
  255. package/skills/askr-cli-vite/agents/openai.yaml +4 -0
  256. package/skills/askr-dashboard-charts/SKILL.md +82 -0
  257. package/skills/askr-dashboard-charts/agents/openai.yaml +4 -0
  258. package/skills/askr-design-system/SKILL.md +86 -0
  259. package/skills/askr-design-system/agents/openai.yaml +4 -0
  260. package/skills/askr-env-config/SKILL.md +74 -0
  261. package/skills/askr-env-config/agents/openai.yaml +4 -0
  262. package/skills/askr-error-loading-empty/SKILL.md +89 -0
  263. package/skills/askr-error-loading-empty/agents/openai.yaml +4 -0
  264. package/skills/askr-file-upload-artifacts/SKILL.md +77 -0
  265. package/skills/askr-file-upload-artifacts/agents/openai.yaml +4 -0
  266. package/skills/askr-forms-tables-crud/SKILL.md +98 -0
  267. package/skills/askr-forms-tables-crud/agents/openai.yaml +4 -0
  268. package/skills/askr-mental-model/SKILL.md +109 -0
  269. package/skills/askr-mental-model/agents/openai.yaml +4 -0
  270. package/skills/askr-migration-react/SKILL.md +81 -0
  271. package/skills/askr-migration-react/agents/openai.yaml +4 -0
  272. package/skills/askr-observability-debugging/SKILL.md +83 -0
  273. package/skills/askr-observability-debugging/agents/openai.yaml +4 -0
  274. package/skills/askr-project-structure/SKILL.md +79 -0
  275. package/skills/askr-project-structure/agents/openai.yaml +4 -0
  276. package/skills/askr-query-mutation/SKILL.md +115 -0
  277. package/skills/askr-query-mutation/agents/openai.yaml +4 -0
  278. package/skills/askr-realtime-streaming/SKILL.md +76 -0
  279. package/skills/askr-realtime-streaming/agents/openai.yaml +4 -0
  280. package/skills/askr-resources-data/SKILL.md +100 -0
  281. package/skills/askr-resources-data/agents/openai.yaml +4 -0
  282. package/skills/askr-routing-layouts/SKILL.md +107 -0
  283. package/skills/askr-routing-layouts/agents/openai.yaml +4 -0
  284. package/skills/askr-runtime-reactivity/SKILL.md +92 -0
  285. package/skills/askr-runtime-reactivity/agents/openai.yaml +4 -0
  286. package/skills/askr-ssr-ssg/SKILL.md +76 -0
  287. package/skills/askr-ssr-ssg/agents/openai.yaml +4 -0
  288. package/skills/askr-testing-determinism/SKILL.md +75 -0
  289. package/skills/askr-testing-determinism/agents/openai.yaml +4 -0
  290. package/skills/askr-theming/SKILL.md +86 -0
  291. package/skills/askr-theming/agents/openai.yaml +4 -0
  292. package/skills/askr-ui-composition/SKILL.md +92 -0
  293. package/skills/askr-ui-composition/agents/openai.yaml +4 -0
  294. package/templates/full-stack/AGENTS.md +12 -0
  295. package/templates/full-stack/README.md +18 -0
  296. package/templates/full-stack/gitignore.template +4 -0
  297. package/templates/full-stack/index.html +14 -0
  298. package/templates/full-stack/package.json +37 -0
  299. package/templates/full-stack/server.ts +13 -0
  300. package/templates/full-stack/src/action-authorizations.ts +10 -0
  301. package/templates/full-stack/src/actions/create-message.ts +10 -0
  302. package/templates/full-stack/src/i18n.ts +8 -0
  303. package/templates/full-stack/src/main.tsx +12 -0
  304. package/templates/full-stack/src/pages/home.tsx +25 -0
  305. package/templates/full-stack/src/pages/layout.tsx +33 -0
  306. package/templates/full-stack/src/pages/not-found.tsx +4 -0
  307. package/templates/full-stack/src/routes.tsx +20 -0
  308. package/templates/full-stack/src/schemas.ts +11 -0
  309. package/templates/full-stack/src/server/action-registry.ts +12 -0
  310. package/templates/full-stack/src/server/actions/create-message.ts +14 -0
  311. package/templates/full-stack/src/server/app.ts +66 -0
  312. package/templates/full-stack/src/server/dependencies.ts +55 -0
  313. package/templates/full-stack/src/server/entry-server.ts +8 -0
  314. package/templates/full-stack/src/telemetry.ts +4 -0
  315. package/templates/full-stack/src/vite-server.d.ts +6 -0
  316. package/templates/full-stack/tests/actions/create-message.test.ts +13 -0
  317. package/templates/full-stack/tsconfig.json +16 -0
  318. package/templates/full-stack/vite.config.ts +11 -0
  319. package/templates/spa/AGENTS.md +60 -0
  320. package/templates/spa/README.md +96 -0
  321. package/templates/spa/gitignore.template +16 -0
  322. package/templates/spa/index.html +13 -0
  323. package/templates/spa/package.json +35 -0
  324. package/templates/spa/src/adapters/operations-client.ts +90 -0
  325. package/templates/spa/src/components/shared/metric-card.tsx +27 -0
  326. package/templates/spa/src/components/shared/status-badge.tsx +24 -0
  327. package/templates/spa/src/features/operations/operations.query.ts +9 -0
  328. package/templates/spa/src/main.tsx +10 -0
  329. package/templates/spa/src/pages/_layout.tsx +9 -0
  330. package/templates/spa/src/pages/_routes.tsx +27 -0
  331. package/templates/spa/src/pages/app/_layout.tsx +94 -0
  332. package/templates/spa/src/pages/app/_routes.tsx +10 -0
  333. package/templates/spa/src/pages/app/admin-home.tsx +152 -0
  334. package/templates/spa/src/pages/app/agent-runs.tsx +93 -0
  335. package/templates/spa/src/pages/app/settings.tsx +91 -0
  336. package/templates/spa/src/pages/auth/_layout.tsx +38 -0
  337. package/templates/spa/src/pages/auth/_routes.tsx +6 -0
  338. package/templates/spa/src/pages/auth/login.tsx +63 -0
  339. package/templates/spa/src/pages/not-found.tsx +22 -0
  340. package/templates/spa/src/pages/public/_layout.tsx +47 -0
  341. package/templates/spa/src/pages/public/_routes.tsx +6 -0
  342. package/templates/spa/src/pages/public/home.tsx +143 -0
  343. package/templates/spa/src/shared/format.ts +12 -0
  344. package/templates/spa/src/shared/navigation.ts +15 -0
  345. package/templates/spa/src/styles/components.css +49 -0
  346. package/templates/spa/src/styles/layout.css +192 -0
  347. package/templates/spa/src/styles/reset.css +44 -0
  348. package/templates/spa/src/styles/theme.css +57 -0
  349. package/templates/spa/src/styles/tokens.css +20 -0
  350. package/templates/spa/src/styles.css +7 -0
  351. package/templates/spa/src/styles.d.ts +1 -0
  352. package/templates/spa/tests/app.test.tsx +37 -0
  353. package/templates/spa/tests/components/shared.test.tsx +12 -0
  354. package/templates/spa/tests/resources.test.ts +22 -0
  355. package/templates/spa/tsconfig.json +20 -0
  356. package/templates/spa/tsconfig.node.json +10 -0
  357. package/templates/spa/vite.config.ts +24 -0
  358. package/templates/spa/vitest.config.ts +17 -0
  359. package/templates/ssg/AGENTS.md +55 -0
  360. package/templates/ssg/README.md +39 -0
  361. package/templates/ssg/gitignore.template +17 -0
  362. package/templates/ssg/index.html +13 -0
  363. package/templates/ssg/package.json +35 -0
  364. package/templates/ssg/src/app.tsx +14 -0
  365. package/templates/ssg/src/components/badge.tsx +3 -0
  366. package/templates/ssg/src/components/counter.tsx +30 -0
  367. package/templates/ssg/src/components/site-shell.tsx +111 -0
  368. package/templates/ssg/src/jsx.d.ts +23 -0
  369. package/templates/ssg/src/main.tsx +8 -0
  370. package/templates/ssg/src/pages/about.tsx +82 -0
  371. package/templates/ssg/src/pages/content.tsx +63 -0
  372. package/templates/ssg/src/pages/example.tsx +97 -0
  373. package/templates/ssg/src/pages/home.tsx +51 -0
  374. package/templates/ssg/src/resources/user.ts +15 -0
  375. package/templates/ssg/src/routes.tsx +15 -0
  376. package/templates/ssg/src/styles.css +89 -0
  377. package/templates/ssg/src/vite-env.d.ts +5 -0
  378. package/templates/ssg/ssg.config.ts +34 -0
  379. package/templates/ssg/tests/app.test.tsx +19 -0
  380. package/templates/ssg/tests/components/counter.test.tsx +18 -0
  381. package/templates/ssg/tests/resources.test.ts +11 -0
  382. package/templates/ssg/tests/ssg-config.test.ts +11 -0
  383. package/templates/ssg/tsconfig.json +20 -0
  384. package/templates/ssg/tsconfig.node.json +10 -0
  385. package/templates/ssg/vite.config.ts +24 -0
  386. package/templates/ssg/vitest.config.ts +17 -0
  387. package/templates/ssr/AGENTS.md +28 -0
  388. package/templates/ssr/README.md +38 -0
  389. package/templates/ssr/gitignore.template +16 -0
  390. package/templates/ssr/index.html +13 -0
  391. package/templates/ssr/package.json +34 -0
  392. package/templates/ssr/server.ts +16 -0
  393. package/templates/ssr/src/app.tsx +21 -0
  394. package/templates/ssr/src/components/counter.tsx +26 -0
  395. package/templates/ssr/src/entry-server.tsx +10 -0
  396. package/templates/ssr/src/main.tsx +11 -0
  397. package/templates/ssr/src/pages/about.tsx +75 -0
  398. package/templates/ssr/src/pages/example.tsx +113 -0
  399. package/templates/ssr/src/pages/home.tsx +56 -0
  400. package/templates/ssr/src/resources/user.ts +15 -0
  401. package/templates/ssr/src/routes.tsx +13 -0
  402. package/templates/ssr/src/styles.css +148 -0
  403. package/templates/ssr/src/vite-server.d.ts +7 -0
  404. package/templates/ssr/tests/app.test.tsx +24 -0
  405. package/templates/ssr/tests/components/counter.test.tsx +13 -0
  406. package/templates/ssr/tests/resources.test.ts +11 -0
  407. package/templates/ssr/tsconfig.json +22 -0
  408. package/templates/ssr/tsconfig.node.json +10 -0
  409. package/templates/ssr/tsconfig.server.json +15 -0
  410. package/templates/ssr/vite.config.ts +25 -0
  411. package/templates/ssr/vitest.config.ts +13 -0
  412. package/templates/startkit/AGENTS.md +77 -0
  413. package/templates/startkit/README.md +192 -0
  414. package/templates/startkit/gitignore.template +16 -0
  415. package/templates/startkit/index.html +13 -0
  416. package/templates/startkit/package.json +35 -0
  417. package/templates/startkit/src/components/app-header.tsx +93 -0
  418. package/templates/startkit/src/components/app-sidebar.tsx +95 -0
  419. package/templates/startkit/src/components/data-table.tsx +80 -0
  420. package/templates/startkit/src/components/empty-state.tsx +13 -0
  421. package/templates/startkit/src/components/page-header.tsx +23 -0
  422. package/templates/startkit/src/components/stat-card.tsx +24 -0
  423. package/templates/startkit/src/features/accounts/account-filters.tsx +61 -0
  424. package/templates/startkit/src/features/accounts/account-table.tsx +79 -0
  425. package/templates/startkit/src/lib/format.ts +31 -0
  426. package/templates/startkit/src/lib/mock-data.ts +441 -0
  427. package/templates/startkit/src/lib/routes.ts +116 -0
  428. package/templates/startkit/src/main.tsx +12 -0
  429. package/templates/startkit/src/pages/_layout.tsx +56 -0
  430. package/templates/startkit/src/pages/auth/_layout.tsx +7 -0
  431. package/templates/startkit/src/pages/auth/login.tsx +129 -0
  432. package/templates/startkit/src/pages/home.tsx +83 -0
  433. package/templates/startkit/src/pages/not-found.tsx +24 -0
  434. package/templates/startkit/src/pages/workspace/_layout.tsx +17 -0
  435. package/templates/startkit/src/pages/workspace/accounts/index.tsx +217 -0
  436. package/templates/startkit/src/pages/workspace/dashboard.tsx +118 -0
  437. package/templates/startkit/src/pages/workspace/settings.tsx +218 -0
  438. package/templates/startkit/src/router.tsx +7 -0
  439. package/templates/startkit/src/routes/auth-config.ts +38 -0
  440. package/templates/startkit/src/routes/auth.ts +8 -0
  441. package/templates/startkit/src/routes/index.ts +28 -0
  442. package/templates/startkit/src/routes/public.ts +8 -0
  443. package/templates/startkit/src/routes/workspace/accounts.ts +8 -0
  444. package/templates/startkit/src/routes/workspace/index.ts +14 -0
  445. package/templates/startkit/src/styles/components.css +396 -0
  446. package/templates/startkit/src/styles/layout.css +192 -0
  447. package/templates/startkit/src/styles/reset.css +38 -0
  448. package/templates/startkit/src/styles/theme.css +76 -0
  449. package/templates/startkit/src/styles/tokens.css +67 -0
  450. package/templates/startkit/src/styles.css +7 -0
  451. package/templates/startkit/src/toast.ts +55 -0
  452. package/templates/startkit/src/utils/join-classes.ts +4 -0
  453. package/templates/startkit/src/vite-env.d.ts +5 -0
  454. package/templates/startkit/tests/app.test.tsx +32 -0
  455. package/templates/startkit/tests/preferences.test.ts +43 -0
  456. package/templates/startkit/tests/resources.test.ts +82 -0
  457. package/templates/startkit/tsconfig.json +20 -0
  458. package/templates/startkit/tsconfig.node.json +10 -0
  459. package/templates/startkit/vite.config.ts +32 -0
  460. package/templates/startkit/vitest.config.ts +13 -0
@@ -0,0 +1,129 @@
1
+ import { state } from '@askrjs/askr';
2
+ import { Link, currentRoute, navigate } from '@askrjs/askr/router';
3
+ import { Button } from '@askrjs/ui/button';
4
+ import { Input } from '@askrjs/ui/input';
5
+ import { Field } from '@askrjs/themes/components';
6
+ import { LockKeyholeIcon, MailIcon } from '@askrjs/lucide';
7
+ import { signIn } from '../../lib/mock-data';
8
+ import {
9
+ dashboardRoute,
10
+ normalizeProtectedRouteTarget,
11
+ } from '../../lib/routes';
12
+ import { showToast } from '../../toast';
13
+
14
+ export default function LoginPage() {
15
+ const [emailState, setEmailState] = state('alex@example.com');
16
+ const [passwordState, setPasswordState] = state('askr1234');
17
+ const [errorTextState, setErrorTextState] = state('');
18
+ const [submittingState, setSubmittingState] = state(false);
19
+ const routeSnapshot = currentRoute();
20
+
21
+ const redirectTarget = () =>
22
+ normalizeProtectedRouteTarget(routeSnapshot.query.get('next')) ||
23
+ dashboardRoute.href;
24
+
25
+ const validate = () => {
26
+ if (!emailState().trim().includes('@')) {
27
+ return 'Enter a valid email address.';
28
+ }
29
+
30
+ if (passwordState().trim().length < 8) {
31
+ return 'Password must be at least 8 characters.';
32
+ }
33
+
34
+ return '';
35
+ };
36
+
37
+ const submit = async (event: Event) => {
38
+ event.preventDefault();
39
+
40
+ const validationError = validate();
41
+ if (validationError) {
42
+ setErrorTextState(validationError);
43
+ return;
44
+ }
45
+
46
+ setSubmittingState(true);
47
+ setErrorTextState('');
48
+
49
+ try {
50
+ await signIn({ email: emailState(), password: passwordState() });
51
+ showToast({
52
+ title: 'Signed in',
53
+ description: 'Welcome back. You can now access protected routes.',
54
+ });
55
+ navigate(redirectTarget(), { history: 'replace' });
56
+ } catch (error) {
57
+ setErrorTextState(
58
+ error instanceof Error ? error.message : 'Could not sign in.'
59
+ );
60
+ setSubmittingState(false);
61
+ }
62
+ };
63
+
64
+ return (
65
+ <section class="auth-page panel">
66
+ <h1>Sign in</h1>
67
+ <p>Use your workspace account to continue.</p>
68
+
69
+ <form class="auth-form" onSubmit={submit}>
70
+ <Field id="login-email">
71
+ <label htmlFor="login-email">Email</label>
72
+ <label class="input-row">
73
+ <MailIcon size={15} aria-hidden="true" />
74
+ <Input
75
+ type="email"
76
+ id="login-email"
77
+ value={emailState()}
78
+ onInput={(event: Event) =>
79
+ setEmailState((event.target as HTMLInputElement).value)
80
+ }
81
+ />
82
+ </label>
83
+ </Field>
84
+
85
+ <Field id="login-password">
86
+ <label htmlFor="login-password">Password</label>
87
+ <label class="input-row">
88
+ <LockKeyholeIcon size={15} aria-hidden="true" />
89
+ <Input
90
+ type="password"
91
+ id="login-password"
92
+ value={passwordState()}
93
+ onInput={(event: Event) =>
94
+ setPasswordState((event.target as HTMLInputElement).value)
95
+ }
96
+ />
97
+ </label>
98
+ </Field>
99
+
100
+ {errorTextState() && (
101
+ <p class="field-error" role="alert">
102
+ {errorTextState()}
103
+ </p>
104
+ )}
105
+
106
+ <Button type="submit" disabled={submittingState()}>
107
+ {submittingState() ? 'Signing in...' : 'Sign in'}
108
+ </Button>
109
+ </form>
110
+
111
+ <div class="auth-links">
112
+ <Link href="/">Back to landing</Link>
113
+ <button
114
+ type="button"
115
+ class="link-button"
116
+ onClick={() =>
117
+ showToast({
118
+ title: 'Reset link sent',
119
+ description:
120
+ 'This is a starter example. Replace with your auth flow.',
121
+ })
122
+ }
123
+ >
124
+ Forgot password?
125
+ </button>
126
+ </div>
127
+ </section>
128
+ );
129
+ }
@@ -0,0 +1,83 @@
1
+ import { Link } from '@askrjs/askr/router';
2
+ import {
3
+ ShieldCheckIcon,
4
+ WorkflowIcon,
5
+ LayoutPanelTopIcon,
6
+ SparklesIcon,
7
+ } from '@askrjs/lucide';
8
+ import { dashboardRoute, loginRoute } from '../lib/routes';
9
+
10
+ const navButtonClass = 'button button-secondary';
11
+
12
+ export default function LandingPage() {
13
+ return (
14
+ <section class="marketing-page">
15
+ <header class="marketing-header">
16
+ <Link href="/" class="brand-link">
17
+ <span class="brand-pill" aria-hidden="true">
18
+ A
19
+ </span>
20
+ <strong>{'{{appName}}'}</strong>
21
+ </Link>
22
+ <div class="marketing-actions">
23
+ <Link href={loginRoute.href} class={navButtonClass}>
24
+ {loginRoute.navLabel}
25
+ </Link>
26
+ </div>
27
+ </header>
28
+
29
+ <div class="hero-block panel">
30
+ <p class="eyebrow">Production-ready starter</p>
31
+ <h1>Build your Askr app like a real product from day one.</h1>
32
+ <p>
33
+ This starter combines Askr, askr-ui, askr-themes, and lucide icons in
34
+ a practical SaaS baseline with semantic pages, composed route trees,
35
+ and shared layouts.
36
+ </p>
37
+ <div class="hero-cta">
38
+ <Link href={dashboardRoute.href} class="button">
39
+ Open dashboard
40
+ </Link>
41
+ <Link href={loginRoute.href} class={navButtonClass}>
42
+ Try login flow
43
+ </Link>
44
+ </div>
45
+ </div>
46
+
47
+ <section class="feature-grid">
48
+ <article class="panel feature-card">
49
+ <WorkflowIcon size={18} aria-hidden="true" />
50
+ <h2>Composed routes</h2>
51
+ <p>
52
+ Public, auth, protected, and 404 routes are assembled from small
53
+ child route modules instead of one large router file.
54
+ </p>
55
+ </article>
56
+ <article class="panel feature-card">
57
+ <LayoutPanelTopIcon size={18} aria-hidden="true" />
58
+ <h2>Composed UI patterns</h2>
59
+ <p>
60
+ Reusable table, headers, empty states, stat cards, sidebar, and top
61
+ app header.
62
+ </p>
63
+ </article>
64
+ <article class="panel feature-card">
65
+ <ShieldCheckIcon size={18} aria-hidden="true" />
66
+ <h2>State and data flow</h2>
67
+ <p>
68
+ Deterministic mock data with loading, empty, error, and mutation
69
+ states.
70
+ </p>
71
+ </article>
72
+ <article class="panel feature-card">
73
+ <SparklesIcon size={18} aria-hidden="true" />
74
+ <h2>Calm visual baseline</h2>
75
+ <p>
76
+ CSS token system, neutral palette, one accent color, and restrained
77
+ depth.
78
+ </p>
79
+ </article>
80
+ </section>
81
+ </section>
82
+ );
83
+ }
@@ -0,0 +1,24 @@
1
+ import { Link } from '@askrjs/askr/router';
2
+
3
+ const navButtonClass = 'button button-secondary';
4
+
5
+ export default function NotFoundPage() {
6
+ return (
7
+ <section class="not-found-page panel">
8
+ <p class="eyebrow">404</p>
9
+ <h1>Page not found</h1>
10
+ <p>
11
+ The route you requested is not mapped in this starter. Use this page to
12
+ wire your own fallback analytics and recovery flow.
13
+ </p>
14
+ <div class="hero-cta">
15
+ <Link href="/dashboard" class="button">
16
+ Go to dashboard
17
+ </Link>
18
+ <Link href="/" class={navButtonClass}>
19
+ Back to landing
20
+ </Link>
21
+ </div>
22
+ </section>
23
+ );
24
+ }
@@ -0,0 +1,17 @@
1
+ import { Shell, ShellMain, ShellNav } from '@askrjs/themes/components';
2
+ import AppHeader from '../../components/app-header';
3
+ import AppSidebar from '../../components/app-sidebar';
4
+
5
+ export default function AppLayout(props: { children?: unknown }) {
6
+ return (
7
+ <Shell variant="sidebar" class="app-shell">
8
+ <ShellNav class="app-shell-nav">
9
+ <AppSidebar />
10
+ </ShellNav>
11
+ <ShellMain class="app-shell-main">
12
+ <AppHeader />
13
+ <div class="app-main">{props.children}</div>
14
+ </ShellMain>
15
+ </Shell>
16
+ );
17
+ }
@@ -0,0 +1,217 @@
1
+ import { state } from '@askrjs/askr';
2
+ import { resource } from '@askrjs/askr/resources';
3
+ import {
4
+ AlertDialog,
5
+ AlertDialogAction,
6
+ AlertDialogCancel,
7
+ AlertDialogContent,
8
+ AlertDialogDescription,
9
+ AlertDialogOverlay,
10
+ AlertDialogPortal,
11
+ AlertDialogTitle,
12
+ AlertDialogTrigger,
13
+ } from '@askrjs/ui/alert-dialog';
14
+ import { Button } from '@askrjs/ui/button';
15
+ import {
16
+ Inline,
17
+ Pagination,
18
+ PaginationContent,
19
+ PaginationItem,
20
+ } from '@askrjs/themes/components';
21
+ import { ArchiveIcon, PlusIcon } from '@askrjs/lucide';
22
+ import PageHeader from '../../../components/page-header';
23
+ import AccountFilters from '../../../features/accounts/account-filters';
24
+ import AccountTable from '../../../features/accounts/account-table';
25
+ import {
26
+ archiveAccounts,
27
+ listAccounts,
28
+ type AccountRecord,
29
+ type AccountStatus,
30
+ } from '../../../lib/mock-data';
31
+ import { showToast } from '../../../toast';
32
+
33
+ export default function AccountsPage() {
34
+ const [queryState, setQueryState] = state('');
35
+ const [statusState, setStatusState] = state<AccountStatus | 'all'>('all');
36
+ const [pageState, setPageState] = state(1);
37
+ const [selectedIdsState, setSelectedIdsState] = state<string[]>([]);
38
+ const [archivingState, setArchivingState] = state(false);
39
+
40
+ const pageSize = 5;
41
+
42
+ const accountsResource = resource(
43
+ async ({ signal }) =>
44
+ listAccounts({
45
+ signal,
46
+ query: queryState(),
47
+ status: statusState(),
48
+ page: pageState(),
49
+ pageSize,
50
+ }),
51
+ [queryState(), statusState(), pageState()]
52
+ );
53
+
54
+ const rows = () => accountsResource.value?.items ?? [];
55
+ const totalPages = () => accountsResource.value?.totalPages ?? 1;
56
+
57
+ const toggleRow = (id: string) => {
58
+ setSelectedIdsState((current) =>
59
+ current.includes(id)
60
+ ? current.filter((value) => value !== id)
61
+ : [...current, id]
62
+ );
63
+ };
64
+
65
+ const resetFilters = () => {
66
+ setQueryState('');
67
+ setStatusState('all');
68
+ setPageState(1);
69
+ };
70
+
71
+ const openRow = (row: AccountRecord) => {
72
+ showToast({
73
+ title: row.name,
74
+ description: `Open account ${row.id} details in your real product workflow.`,
75
+ });
76
+ };
77
+
78
+ const archiveSelected = async () => {
79
+ if (selectedIdsState().length === 0) {
80
+ return;
81
+ }
82
+
83
+ setArchivingState(true);
84
+
85
+ try {
86
+ const result = await archiveAccounts({ ids: selectedIdsState() });
87
+ setSelectedIdsState([]);
88
+ showToast({
89
+ title: 'Accounts archived',
90
+ description: `${result.archived} account records moved to archived status.`,
91
+ });
92
+ await accountsResource.refresh();
93
+ } catch (error) {
94
+ showToast({
95
+ title: 'Archive failed',
96
+ description:
97
+ error instanceof Error
98
+ ? error.message
99
+ : 'Could not archive selected rows.',
100
+ });
101
+ } finally {
102
+ setArchivingState(false);
103
+ }
104
+ };
105
+
106
+ return (
107
+ <section class="stack-lg">
108
+ <PageHeader
109
+ title="Accounts"
110
+ description="Search, filter, page, and run row actions against account records."
111
+ actions={
112
+ <Button
113
+ onPress={() =>
114
+ showToast({
115
+ title: 'Create account',
116
+ description:
117
+ 'Wire this button into your real create-account form flow.',
118
+ })
119
+ }
120
+ >
121
+ <PlusIcon size={14} aria-hidden="true" /> Add account
122
+ </Button>
123
+ }
124
+ />
125
+
126
+ <section class="panel stack-md">
127
+ <AccountFilters
128
+ query={queryState()}
129
+ status={statusState()}
130
+ onQueryChange={(next) => {
131
+ setQueryState(next);
132
+ setPageState(1);
133
+ }}
134
+ onStatusChange={(next) => {
135
+ setStatusState(next);
136
+ setPageState(1);
137
+ }}
138
+ onReset={resetFilters}
139
+ />
140
+
141
+ <AccountTable
142
+ rows={rows}
143
+ selectedIds={selectedIdsState}
144
+ onToggleRow={toggleRow}
145
+ onOpenRow={openRow}
146
+ loading={accountsResource.pending && !accountsResource.value}
147
+ errorText={accountsResource.error?.message ?? null}
148
+ />
149
+
150
+ <Inline align="center" gap="var(--ak-space-lg)" wrap="wrap">
151
+ <span class="muted">{selectedIdsState().length} selected</span>
152
+
153
+ <AlertDialog>
154
+ <AlertDialogTrigger asChild>
155
+ <Button
156
+ disabled={selectedIdsState().length === 0}
157
+ class="button-secondary"
158
+ >
159
+ <ArchiveIcon size={14} aria-hidden="true" /> Archive selected
160
+ </Button>
161
+ </AlertDialogTrigger>
162
+ <AlertDialogPortal>
163
+ <AlertDialogOverlay />
164
+ <AlertDialogContent class="panel stack-md">
165
+ <AlertDialogTitle>Archive selected accounts?</AlertDialogTitle>
166
+ <AlertDialogDescription>
167
+ This updates selected account records in the mock data source.
168
+ </AlertDialogDescription>
169
+ <div class="inline-end">
170
+ <AlertDialogCancel asChild>
171
+ <Button class="button-secondary">Cancel</Button>
172
+ </AlertDialogCancel>
173
+ <AlertDialogAction asChild>
174
+ <Button
175
+ onPress={() => void archiveSelected()}
176
+ disabled={archivingState()}
177
+ >
178
+ {archivingState() ? 'Archiving...' : 'Confirm archive'}
179
+ </Button>
180
+ </AlertDialogAction>
181
+ </div>
182
+ </AlertDialogContent>
183
+ </AlertDialogPortal>
184
+ </AlertDialog>
185
+
186
+ <Pagination aria-label="Accounts pages">
187
+ <PaginationContent>
188
+ <PaginationItem>
189
+ <Button
190
+ class="button-secondary"
191
+ disabled={pageState() <= 1}
192
+ onPress={() => setPageState((page) => page - 1)}
193
+ >
194
+ Previous
195
+ </Button>
196
+ </PaginationItem>
197
+ <PaginationItem>
198
+ <span aria-current="page">
199
+ Page {pageState()} of {totalPages()}
200
+ </span>
201
+ </PaginationItem>
202
+ <PaginationItem>
203
+ <Button
204
+ class="button-secondary"
205
+ disabled={pageState() >= totalPages()}
206
+ onPress={() => setPageState((page) => page + 1)}
207
+ >
208
+ Next
209
+ </Button>
210
+ </PaginationItem>
211
+ </PaginationContent>
212
+ </Pagination>
213
+ </Inline>
214
+ </section>
215
+ </section>
216
+ );
217
+ }
@@ -0,0 +1,118 @@
1
+ import { state } from '@askrjs/askr';
2
+ import { resource } from '@askrjs/askr/resources';
3
+ import { Button } from '@askrjs/ui/button';
4
+ import {
5
+ BarChart3Icon,
6
+ CircleDollarSignIcon,
7
+ Clock3Icon,
8
+ UsersIcon,
9
+ } from '@askrjs/lucide';
10
+ import DataTable, { type DataTableColumn } from '../../components/data-table';
11
+ import EmptyState from '../../components/empty-state';
12
+ import PageHeader from '../../components/page-header';
13
+ import StatCard from '../../components/stat-card';
14
+ import { getDashboardData, type ActivityEntry } from '../../lib/mock-data';
15
+ import { formatRelativeDate } from '../../lib/format';
16
+
17
+ export default function DashboardPage() {
18
+ const [hideActivityState, setHideActivityState] = state(false);
19
+ const dashboardResource = resource(
20
+ async ({ signal }) => getDashboardData({ signal }),
21
+ []
22
+ );
23
+
24
+ const stats = () => dashboardResource.value?.stats ?? [];
25
+ const activities = () =>
26
+ hideActivityState() ? [] : (dashboardResource.value?.activities ?? []);
27
+
28
+ const columns: DataTableColumn<ActivityEntry>[] = [
29
+ { key: 'actor', header: 'Actor', render: (row) => row.actor },
30
+ { key: 'action', header: 'Action', render: (row) => row.action },
31
+ { key: 'resource', header: 'Resource', render: (row) => row.resource },
32
+ {
33
+ key: 'timestamp',
34
+ header: 'When',
35
+ render: (row) => (
36
+ <span class="muted">{formatRelativeDate(row.timestamp)}</span>
37
+ ),
38
+ },
39
+ ];
40
+
41
+ const iconByStatKey = {
42
+ mrr: CircleDollarSignIcon,
43
+ accounts: UsersIcon,
44
+ pending: Clock3Icon,
45
+ seats: BarChart3Icon,
46
+ } as const;
47
+
48
+ return (
49
+ <section class="stack-lg">
50
+ <PageHeader
51
+ title="Dashboard"
52
+ description="Overview of workspace health, growth, and recent team activity."
53
+ actions={
54
+ <Button
55
+ onPress={() => dashboardResource.refresh()}
56
+ disabled={dashboardResource.pending}
57
+ >
58
+ {dashboardResource.pending ? 'Refreshing...' : 'Refresh'}
59
+ </Button>
60
+ }
61
+ />
62
+
63
+ <div class="stat-grid">
64
+ {stats().map((stat) => {
65
+ const Icon =
66
+ iconByStatKey[stat.key as keyof typeof iconByStatKey] ??
67
+ BarChart3Icon;
68
+ return (
69
+ <StatCard
70
+ label={stat.label}
71
+ value={stat.value}
72
+ trend={stat.trend}
73
+ icon={Icon}
74
+ />
75
+ );
76
+ })}
77
+ </div>
78
+
79
+ <section class="panel stack-md">
80
+ <div class="section-head">
81
+ <div>
82
+ <h2>Recent activity</h2>
83
+ <p class="muted">
84
+ The activity table demonstrates loading, empty, and retry
85
+ behavior.
86
+ </p>
87
+ </div>
88
+ <Button
89
+ onPress={() => setHideActivityState((current) => !current)}
90
+ class="button-secondary"
91
+ disabled={dashboardResource.pending}
92
+ >
93
+ {hideActivityState() ? 'Show activity' : 'Show empty state'}
94
+ </Button>
95
+ </div>
96
+
97
+ {dashboardResource.error ? (
98
+ <EmptyState
99
+ title="Could not load dashboard"
100
+ description={dashboardResource.error.message}
101
+ action={
102
+ <Button onPress={() => dashboardResource.refresh()}>Retry</Button>
103
+ }
104
+ />
105
+ ) : (
106
+ <DataTable
107
+ rows={activities}
108
+ rowKey={(row) => row.id}
109
+ columns={columns}
110
+ isLoading={dashboardResource.pending && !dashboardResource.value}
111
+ emptyTitle="No activity yet"
112
+ emptyDescription="Your activity feed will appear as soon as workspace events are recorded."
113
+ />
114
+ )}
115
+ </section>
116
+ </section>
117
+ );
118
+ }