@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,192 @@
1
+ # {{appName}} starter kit
2
+
3
+ A production-ready Askr starter built to feel like a real product from day one.
4
+
5
+ It ships with opinionated defaults for routing boundaries, layout composition,
6
+ state handling, and interface polish so you can focus on product behavior instead
7
+ of project plumbing.
8
+
9
+ Stack:
10
+
11
+ - `@askrjs/askr`
12
+ - `@askrjs/auth`
13
+ - `@askrjs/ui`
14
+ - `@askrjs/themes` (default)
15
+ - Lucide icons via `@askrjs/lucide`
16
+ - plain CSS with layers and design tokens
17
+
18
+ ## Quick start
19
+
20
+ ```bash
21
+ npm install
22
+ npm run dev
23
+ ```
24
+
25
+ Then run quality checks before your first commit:
26
+
27
+ ```bash
28
+ npm run check
29
+ npm run fmt:check
30
+ ```
31
+
32
+ ## Command reference
33
+
34
+ ```bash
35
+ npm run dev # Local dev server with HMR
36
+ npm run build # Production build
37
+ npm run preview # Preview production build
38
+ npm run typecheck # TypeScript checks
39
+ npm run lint # ESLint across project files
40
+ npm test # Vitest suite
41
+ npm run fmt # Format full project with Prettier
42
+ npm run fmt:check # Verify formatting
43
+ npm run check # lint + typecheck + tests + production build
44
+ ```
45
+
46
+ ## Routes and layout model
47
+
48
+ Routes are registered in src/router.tsx and split into explicit groups:
49
+
50
+ - Public routes: / (landing)
51
+ - Auth routes: /login (centered auth layout)
52
+ - Protected routes: /dashboard, /accounts, /settings (app shell layout)
53
+ - Fallback route: /\* (not found)
54
+
55
+ The root app wrapper in `src/pages/_layout.tsx` owns cross-cutting UI such as toast.
56
+
57
+ ## Project structure
58
+
59
+ ```text
60
+ src/
61
+ main.tsx
62
+ router.tsx
63
+
64
+ routes/
65
+ index.ts
66
+ auth.ts
67
+ auth-config.ts
68
+ public.ts
69
+ workspace/
70
+ index.ts
71
+ accounts.ts
72
+
73
+ pages/
74
+ _layout.tsx
75
+ home.tsx
76
+ not-found.tsx
77
+ auth/
78
+ _layout.tsx
79
+ login.tsx
80
+ workspace/
81
+ _layout.tsx
82
+ dashboard.tsx
83
+ settings.tsx
84
+ accounts/
85
+ index.tsx
86
+
87
+ components/
88
+ app-sidebar.tsx
89
+ app-header.tsx
90
+ stat-card.tsx
91
+ data-table.tsx
92
+ empty-state.tsx
93
+ page-header.tsx
94
+
95
+ features/
96
+ accounts/
97
+ account-table.tsx
98
+ account-filters.tsx
99
+
100
+ lib/
101
+ mock-data.ts
102
+ format.ts
103
+ routes.ts
104
+
105
+ styles.css
106
+ styles/
107
+ reset.css
108
+ tokens.css
109
+ theme.css
110
+ layout.css
111
+ components.css
112
+ ```
113
+
114
+ ## How routing works
115
+
116
+ `src/router.tsx` creates one registry with `createRouteRegistry()`. The files in
117
+ `src/routes` compose its `group()` and `route()` declarations:
118
+
119
+ - A shared root wrapper for providers
120
+ - Auth layout only for /login
121
+ - App layout only for protected routes
122
+ - Function-based auth requirements redirect unauthenticated users from protected routes to /login
123
+
124
+ This keeps route ownership clear and avoids one mega-layout for every page type.
125
+
126
+ ## How layouts work
127
+
128
+ - App layout (`src/pages/workspace/_layout.tsx`): sidebar + sticky header + content area.
129
+ - Auth layout (`src/pages/auth/_layout.tsx`): minimal centered shell for forms.
130
+
131
+ Use app layout for authenticated product surfaces and auth layout for onboarding/login flows.
132
+
133
+ ## How to add a page
134
+
135
+ 1. Create a new page file in the matching branch under `src/pages`.
136
+ 2. Register it in the matching file under `src/routes`.
137
+ 3. Place the route in the correct layout group (public, auth, protected).
138
+ 4. If protected, use the existing function requirements such as `requireUser()`,
139
+ `requireRole()`, or `requirePermission()` at the narrowest owning route or group.
140
+
141
+ ## First-hour customization checklist
142
+
143
+ 1. Update brand name, colors, and typography tokens in src/styles/tokens.css.
144
+ 2. Replace mock user/session data in src/lib/mock-data.ts.
145
+ 3. Swap dashboard/account samples for domain-specific features.
146
+ 4. Wire login and route auth logic to your real auth provider.
147
+ 5. Replace placeholders in landing and settings copy with product language.
148
+ 6. Add one end-to-end happy-path test for your primary workflow.
149
+
150
+ ## How to add a component
151
+
152
+ 1. Put shared UI in `src/components`.
153
+ 2. Put domain-specific pieces in `src/features/<feature-name>`.
154
+ 3. Keep component APIs prop-driven and small.
155
+ 4. Prefer composing `@askrjs/ui` and `@askrjs/themes/components` before inventing new abstractions.
156
+
157
+ ## Styling organization
158
+
159
+ The CSS architecture is intentionally layered:
160
+
161
+ - reset.css: baseline resets
162
+ - tokens.css: design tokens (colors, spacing, type scale, radius)
163
+ - theme.css: global typography and high-level theme values
164
+ - layout.css: page/shell structure and responsive behavior
165
+ - components.css: component and slot-level styling
166
+
167
+ Guidelines:
168
+
169
+ - Use token variables for spacing and colors.
170
+ - Keep a calm neutral palette and one accent color.
171
+ - Prefer subtle borders over heavy shadows.
172
+ - Keep radius and motion restrained.
173
+
174
+ ## UX patterns included
175
+
176
+ - Loading states (skeletons)
177
+ - Empty states
178
+ - Error states
179
+ - Disabled actions
180
+ - Form validation examples
181
+ - Toast example
182
+ - Modal example
183
+
184
+ ## Notes
185
+
186
+ Data is intentionally mock-only and deterministic.
187
+
188
+ When integrating backend services:
189
+
190
+ 1. Keep API calls and data transforms in src/lib.
191
+ 2. Preserve AbortController signal forwarding in async operations.
192
+ 3. Keep route guards and layout boundaries explicit in src/router.tsx.
@@ -0,0 +1,16 @@
1
+ node_modules/
2
+ dist/
3
+ build/
4
+ .env.local
5
+ .env.*.local
6
+ npm-debug.log*
7
+ yarn-debug.log*
8
+ yarn-error.log*
9
+ pnpm-debug.log*
10
+ .DS_Store
11
+ Thumbs.db
12
+ .vscode/
13
+ .idea/
14
+ *.swp
15
+ *.swo
16
+ *~
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>{{appName}}</title>
8
+ </head>
9
+ <body>
10
+ <div id="app"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "{{appName}}",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vp dev",
7
+ "build": "vp build",
8
+ "preview": "vp preview",
9
+ "test": "vp test run",
10
+ "test:watch": "vp test --watch",
11
+ "typecheck": "tsc --noEmit",
12
+ "lint": "vp lint .",
13
+ "lint:fix": "npm run lint -- --fix",
14
+ "fmt": "vp fmt .",
15
+ "fmt:check": "vp fmt --check .",
16
+ "check": "npm run lint && npm run typecheck && npm test && npm run build"
17
+ },
18
+ "dependencies": {
19
+ "@askrjs/askr": ">=0.0.53 <0.1.0",
20
+ "@askrjs/auth": ">=0.0.1 <0.1.0",
21
+ "@askrjs/lucide": ">=0.0.3 <0.1.0",
22
+ "@askrjs/themes": ">=0.0.12 <0.1.0",
23
+ "@askrjs/ui": ">=0.0.13 <0.1.0"
24
+ },
25
+ "devDependencies": {
26
+ "@askrjs/vite": ">=0.0.6 <0.1.0",
27
+ "@types/node": "^26.0.0",
28
+ "jsdom": "^29.1.1",
29
+ "typescript": "^6.0.3",
30
+ "vite-plus": "^0.2.4"
31
+ },
32
+ "engines": {
33
+ "node": "^20.19.0 || >=22.12.0"
34
+ }
35
+ }
@@ -0,0 +1,93 @@
1
+ import { currentRoute, Link } from '@askrjs/askr/router';
2
+ import { Input } from '@askrjs/ui/input';
3
+ import {
4
+ Avatar,
5
+ AvatarFallback,
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuGroup,
9
+ DropdownMenuItem,
10
+ DropdownMenuLabel,
11
+ DropdownMenuPortal,
12
+ DropdownMenuSeparator,
13
+ DropdownMenuTrigger,
14
+ Inline,
15
+ } from '@askrjs/themes/components';
16
+ import { SearchIcon } from '@askrjs/lucide';
17
+ import { buildLoginHref, getRouteLabel, settingsRoute } from '../lib/routes';
18
+ import { showToast } from '../toast';
19
+ import { signOut } from '../lib/mock-data';
20
+
21
+ export default function AppHeader() {
22
+ const breadcrumb = () => getRouteLabel(currentRoute().path);
23
+
24
+ return (
25
+ <header class="app-header">
26
+ <Inline
27
+ align="center"
28
+ justify="between"
29
+ gap="var(--ak-space-lg)"
30
+ wrap="wrap"
31
+ >
32
+ <div class="breadcrumbs">
33
+ <span>App</span>
34
+ <span aria-hidden="true">/</span>
35
+ <strong>{breadcrumb()}</strong>
36
+ </div>
37
+
38
+ <label class="header-search" aria-label="Search">
39
+ <SearchIcon size={15} aria-hidden="true" />
40
+ <Input placeholder="Search docs, accounts, settings..." disabled />
41
+ </label>
42
+
43
+ <DropdownMenu>
44
+ <DropdownMenuTrigger class="header-account-trigger">
45
+ <Avatar>
46
+ <AvatarFallback>AM</AvatarFallback>
47
+ </Avatar>
48
+ <span class="header-account-name">Alex Morgan</span>
49
+ </DropdownMenuTrigger>
50
+ <DropdownMenuPortal>
51
+ <DropdownMenuContent side="bottom" align="end" sideOffset={8}>
52
+ <DropdownMenuLabel>Workspace</DropdownMenuLabel>
53
+ <DropdownMenuGroup>
54
+ <DropdownMenuItem asChild>
55
+ <Link href={settingsRoute.href}>Profile settings</Link>
56
+ </DropdownMenuItem>
57
+ <DropdownMenuItem
58
+ onSelect={() =>
59
+ showToast({
60
+ title: 'Notifications enabled',
61
+ description:
62
+ 'Connect this action to your notification center.',
63
+ })
64
+ }
65
+ >
66
+ Notifications
67
+ </DropdownMenuItem>
68
+ </DropdownMenuGroup>
69
+ <DropdownMenuSeparator />
70
+ <DropdownMenuItem
71
+ onSelect={() => {
72
+ const nextTarget =
73
+ typeof window === 'undefined'
74
+ ? undefined
75
+ : `${window.location.pathname}${window.location.search}${window.location.hash}`;
76
+ signOut();
77
+ showToast({
78
+ title: 'Signed out',
79
+ description:
80
+ 'Session state is now cleared from local storage.',
81
+ });
82
+ window.location.assign(buildLoginHref(nextTarget));
83
+ }}
84
+ >
85
+ Sign out
86
+ </DropdownMenuItem>
87
+ </DropdownMenuContent>
88
+ </DropdownMenuPortal>
89
+ </DropdownMenu>
90
+ </Inline>
91
+ </header>
92
+ );
93
+ }
@@ -0,0 +1,95 @@
1
+ import { Link } from '@askrjs/askr/router';
2
+ import {
3
+ LayoutDashboardIcon,
4
+ UsersIcon,
5
+ SettingsIcon,
6
+ LayersIcon,
7
+ ShieldCheckIcon,
8
+ } from '@askrjs/lucide';
9
+ import type { IconProps } from '@askrjs/lucide';
10
+ import type { JSXElement } from '@askrjs/askr/foundations';
11
+ import { NavBrand, NavGroup, NavLink, Navbar } from '@askrjs/themes/components';
12
+ import {
13
+ accountsRoute,
14
+ dashboardRoute,
15
+ landingRoute,
16
+ loginRoute,
17
+ settingsRoute,
18
+ } from '../lib/routes';
19
+
20
+ type NavItem = {
21
+ href: string;
22
+ label: string;
23
+ icon: (props: IconProps) => JSXElement;
24
+ };
25
+
26
+ const primaryNav: NavItem[] = [
27
+ {
28
+ href: dashboardRoute.href,
29
+ label: dashboardRoute.navLabel,
30
+ icon: LayoutDashboardIcon,
31
+ },
32
+ {
33
+ href: accountsRoute.href,
34
+ label: accountsRoute.navLabel,
35
+ icon: UsersIcon,
36
+ },
37
+ {
38
+ href: settingsRoute.href,
39
+ label: settingsRoute.navLabel,
40
+ icon: SettingsIcon,
41
+ },
42
+ ];
43
+
44
+ const secondaryNav: NavItem[] = [
45
+ { href: landingRoute.href, label: 'Marketing site', icon: LayersIcon },
46
+ { href: loginRoute.href, label: 'Auth entry', icon: ShieldCheckIcon },
47
+ ];
48
+
49
+ export default function AppSidebar() {
50
+ return (
51
+ <aside class="app-sidebar" aria-label="Sidebar navigation">
52
+ <Navbar
53
+ orientation="vertical"
54
+ class="app-sidebar-nav"
55
+ aria-label="Sidebar navigation"
56
+ >
57
+ <NavBrand>
58
+ <Link href={dashboardRoute.href} class="sidebar-brand">
59
+ <span class="brand-pill" aria-hidden="true">
60
+ A
61
+ </span>
62
+ <div>
63
+ <p class="sidebar-title">{'{{appName}}'}</p>
64
+ <p class="sidebar-subtitle">Starter Kit</p>
65
+ </div>
66
+ </Link>
67
+ </NavBrand>
68
+
69
+ <NavGroup id="workspace-nav-group" label="Workspace">
70
+ {primaryNav.map((item) => {
71
+ const Icon = item.icon;
72
+ return (
73
+ <NavLink href={item.href}>
74
+ <Icon size={16} aria-hidden={true} />
75
+ <span>{item.label}</span>
76
+ </NavLink>
77
+ );
78
+ })}
79
+ </NavGroup>
80
+
81
+ <NavGroup id="other-nav-group" label="Other" placement="bottom">
82
+ {secondaryNav.map((item) => {
83
+ const Icon = item.icon;
84
+ return (
85
+ <NavLink href={item.href}>
86
+ <Icon size={16} aria-hidden={true} />
87
+ <span>{item.label}</span>
88
+ </NavLink>
89
+ );
90
+ })}
91
+ </NavGroup>
92
+ </Navbar>
93
+ </aside>
94
+ );
95
+ }
@@ -0,0 +1,80 @@
1
+ import { For } from '@askrjs/askr/control';
2
+ import { Skeleton } from '@askrjs/themes/components';
3
+ import EmptyState from './empty-state';
4
+ import { joinClasses } from '../utils/join-classes';
5
+
6
+ export type DataTableColumn<Row> = {
7
+ key: string;
8
+ header: unknown;
9
+ class?: string;
10
+ render: (row: Row) => unknown;
11
+ };
12
+
13
+ export default function DataTable<Row>(props: {
14
+ rows: () => Row[];
15
+ rowKey: (row: Row) => string;
16
+ columns: DataTableColumn<Row>[];
17
+ class?: string;
18
+ tableClass?: string;
19
+ rowClass?: (row: Row) => string | undefined;
20
+ isLoading?: boolean;
21
+ errorText?: string | null;
22
+ emptyTitle?: string;
23
+ emptyDescription?: string;
24
+ }) {
25
+ if (props.errorText) {
26
+ return (
27
+ <EmptyState title="Could not load table" description={props.errorText} />
28
+ );
29
+ }
30
+
31
+ if (props.isLoading) {
32
+ return (
33
+ <div
34
+ class={joinClasses('panel stack-sm', props.class)}
35
+ aria-hidden="true"
36
+ >
37
+ <Skeleton class="skeleton-line" />
38
+ <Skeleton class="skeleton-line" />
39
+ <Skeleton class="skeleton-line" />
40
+ </div>
41
+ );
42
+ }
43
+
44
+ if (props.rows().length === 0) {
45
+ return (
46
+ <EmptyState
47
+ title={props.emptyTitle ?? 'No rows found'}
48
+ description={
49
+ props.emptyDescription ??
50
+ 'Try changing filters or adding new records.'
51
+ }
52
+ />
53
+ );
54
+ }
55
+
56
+ return (
57
+ <div class={joinClasses('table-wrap', props.class)}>
58
+ <table class={props.tableClass}>
59
+ <thead>
60
+ <tr>
61
+ {props.columns.map((column) => (
62
+ <th class={column.class}>{column.header}</th>
63
+ ))}
64
+ </tr>
65
+ </thead>
66
+ <tbody>
67
+ <For each={props.rows} by={props.rowKey}>
68
+ {(row: Row) => (
69
+ <tr class={props.rowClass?.(row)}>
70
+ {props.columns.map((column) => (
71
+ <td class={column.class}>{column.render(row)}</td>
72
+ ))}
73
+ </tr>
74
+ )}
75
+ </For>
76
+ </tbody>
77
+ </table>
78
+ </div>
79
+ );
80
+ }
@@ -0,0 +1,13 @@
1
+ export default function EmptyState(props: {
2
+ title: string;
3
+ description: string;
4
+ action?: unknown;
5
+ }) {
6
+ return (
7
+ <section class="empty-state panel" role="status">
8
+ <h2>{props.title}</h2>
9
+ <p>{props.description}</p>
10
+ {props.action && <div>{props.action}</div>}
11
+ </section>
12
+ );
13
+ }
@@ -0,0 +1,23 @@
1
+ import { Inline } from '@askrjs/themes/components';
2
+
3
+ export default function PageHeader(props: {
4
+ title: string;
5
+ description: string;
6
+ actions?: unknown;
7
+ }) {
8
+ return (
9
+ <Inline
10
+ class="page-header"
11
+ align="center"
12
+ justify="between"
13
+ gap="var(--ak-space-lg)"
14
+ wrap="wrap"
15
+ >
16
+ <div class="page-header-copy">
17
+ <h1>{props.title}</h1>
18
+ <p>{props.description}</p>
19
+ </div>
20
+ {props.actions && <div>{props.actions}</div>}
21
+ </Inline>
22
+ );
23
+ }
@@ -0,0 +1,24 @@
1
+ import type { JSXElement } from '@askrjs/askr/foundations';
2
+ import type { IconProps } from '@askrjs/lucide';
3
+
4
+ type IconComponent = (props: IconProps) => JSXElement;
5
+
6
+ export default function StatCard(props: {
7
+ label: string;
8
+ value: string;
9
+ trend: string;
10
+ icon: IconComponent;
11
+ }) {
12
+ const Icon = props.icon;
13
+
14
+ return (
15
+ <article class="panel stat-card">
16
+ <div class="stat-card-head">
17
+ <p>{props.label}</p>
18
+ <Icon size={16} aria-hidden="true" />
19
+ </div>
20
+ <strong>{props.value}</strong>
21
+ <p class="trend">{props.trend}</p>
22
+ </article>
23
+ );
24
+ }
@@ -0,0 +1,61 @@
1
+ import { Input } from '@askrjs/ui/input';
2
+ import { SearchIcon } from '@askrjs/lucide';
3
+ import {
4
+ Select,
5
+ SelectContent,
6
+ SelectItem,
7
+ SelectPortal,
8
+ SelectTrigger,
9
+ SelectValue,
10
+ } from '@askrjs/ui/select';
11
+ import { Button } from '@askrjs/ui/button';
12
+ import type { AccountStatus } from '../../lib/mock-data';
13
+
14
+ export default function AccountFilters(props: {
15
+ query: string;
16
+ status: AccountStatus | 'all';
17
+ onQueryChange: (next: string) => void;
18
+ onStatusChange: (next: AccountStatus | 'all') => void;
19
+ onReset: () => void;
20
+ }) {
21
+ const hasFilters = () =>
22
+ props.query.trim().length > 0 || props.status !== 'all';
23
+
24
+ return (
25
+ <div class="account-filters">
26
+ <label class="input-row account-search" aria-label="Search accounts">
27
+ <SearchIcon size={15} aria-hidden="true" />
28
+ <Input
29
+ placeholder="Search by name, email, or id"
30
+ value={props.query}
31
+ onInput={(event: Event) =>
32
+ props.onQueryChange((event.target as HTMLInputElement).value)
33
+ }
34
+ />
35
+ </label>
36
+
37
+ <Select
38
+ value={props.status}
39
+ onValueChange={(value) =>
40
+ props.onStatusChange(value as AccountStatus | 'all')
41
+ }
42
+ >
43
+ <SelectTrigger aria-label="Status filter">
44
+ <SelectValue placeholder="Filter by status" />
45
+ </SelectTrigger>
46
+ <SelectPortal>
47
+ <SelectContent>
48
+ <SelectItem value="all">All statuses</SelectItem>
49
+ <SelectItem value="active">Active</SelectItem>
50
+ <SelectItem value="pending">Pending</SelectItem>
51
+ <SelectItem value="archived">Archived</SelectItem>
52
+ </SelectContent>
53
+ </SelectPortal>
54
+ </Select>
55
+
56
+ <Button onPress={props.onReset} disabled={!hasFilters()}>
57
+ Clear filters
58
+ </Button>
59
+ </div>
60
+ );
61
+ }