@askrjs/cli 0.0.3 → 0.0.4

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 (287) hide show
  1. package/README.md +37 -0
  2. package/dist/add.d.ts +16 -0
  3. package/dist/add.js +33 -29
  4. package/dist/cli.d.ts +5 -0
  5. package/dist/cli.js +0 -2
  6. package/dist/create.d.ts +5 -0
  7. package/dist/create.js +104 -26
  8. package/dist/directory-swap-DWoHtx7C.js +35 -0
  9. package/dist/discovery-Difb7Y4G.js +0 -2
  10. package/dist/generate.d.ts +5 -0
  11. package/dist/generate.js +77 -12
  12. package/dist/is-direct-execution-Cdlr-ZUl.js +0 -2
  13. package/dist/openapi.d.ts +25 -0
  14. package/dist/openapi.js +44 -12
  15. package/dist/planner-VAj7qlxr.js +0 -2
  16. package/dist/range-YUs9eimn.js +0 -2
  17. package/dist/registry-CyrRHRG5.js +0 -2
  18. package/dist/skills/askr-ssr-ssg/SKILL.md +3 -1
  19. package/dist/{skills-Bh0mEhIx.js → skills-B7CbWur9.js} +89 -26
  20. package/dist/skills.d.ts +18 -0
  21. package/dist/skills.js +1 -1
  22. package/dist/specification-DXnDOC-0.js +0 -2
  23. package/dist/ssg-config.d.ts +41 -0
  24. package/dist/ssg-config.js +1 -0
  25. package/dist/ssg.d.ts +61 -0
  26. package/dist/ssg.js +360 -24
  27. package/dist/templates/full-stack/package.json +1 -1
  28. package/dist/templates/full-stack/src/server/action-registry.ts +0 -1
  29. package/dist/templates/full-stack/tsconfig.json +1 -1
  30. package/dist/templates/spa/package.json +2 -3
  31. package/dist/templates/spa/src/pages/app/_routes.tsx +2 -0
  32. package/dist/templates/spa/src/pages/public/_routes.tsx +2 -0
  33. package/dist/templates/spa/tsconfig.json +2 -1
  34. package/dist/templates/spa/vitest.config.ts +0 -4
  35. package/dist/templates/ssg/README.md +1 -1
  36. package/dist/templates/ssg/package.json +1 -1
  37. package/dist/templates/ssg/ssg.config.ts +7 -0
  38. package/dist/templates/ssg/tests/ssg-config.test.ts +2 -0
  39. package/dist/templates/ssg/tsconfig.json +2 -1
  40. package/dist/templates/ssg/vitest.config.ts +0 -4
  41. package/dist/templates/ssr/package.json +2 -2
  42. package/dist/templates/startkit/package.json +2 -2
  43. package/dist/templates/startkit/src/lib/mock-data.ts +17 -39
  44. package/dist/templates/startkit/tsconfig.json +2 -1
  45. package/dist/update.d.ts +41 -0
  46. package/dist/update.js +0 -2
  47. package/dist/writer-D8qe_7ud.js +0 -2
  48. package/package.json +13 -8
  49. package/dist/add.js.map +0 -1
  50. package/dist/cli.js.map +0 -1
  51. package/dist/create.js.map +0 -1
  52. package/dist/discovery-Difb7Y4G.js.map +0 -1
  53. package/dist/generate.js.map +0 -1
  54. package/dist/is-direct-execution-Cdlr-ZUl.js.map +0 -1
  55. package/dist/openapi.js.map +0 -1
  56. package/dist/planner-VAj7qlxr.js.map +0 -1
  57. package/dist/range-YUs9eimn.js.map +0 -1
  58. package/dist/registry-CyrRHRG5.js.map +0 -1
  59. package/dist/skills-Bh0mEhIx.js.map +0 -1
  60. package/dist/specification-DXnDOC-0.js.map +0 -1
  61. package/dist/ssg.js.map +0 -1
  62. package/dist/templates/full-stack/src/vite-server.d.ts +0 -5
  63. package/dist/templates/spa/src/styles.d.ts +0 -1
  64. package/dist/templates/ssg/src/vite-env.d.ts +0 -5
  65. package/dist/templates/ssr/src/vite-server.d.ts +0 -7
  66. package/dist/templates/startkit/src/vite-env.d.ts +0 -5
  67. package/dist/update.js.map +0 -1
  68. package/dist/writer-D8qe_7ud.js.map +0 -1
  69. package/skills/askr-accessibility/SKILL.md +0 -68
  70. package/skills/askr-accessibility/agents/openai.yaml +0 -4
  71. package/skills/askr-agent-execution/SKILL.md +0 -85
  72. package/skills/askr-agent-execution/agents/openai.yaml +0 -4
  73. package/skills/askr-agent-workflows/SKILL.md +0 -57
  74. package/skills/askr-agent-workflows/agents/openai.yaml +0 -4
  75. package/skills/askr-api-integration/SKILL.md +0 -79
  76. package/skills/askr-api-integration/agents/openai.yaml +0 -4
  77. package/skills/askr-app-builder/SKILL.md +0 -99
  78. package/skills/askr-app-builder/agents/openai.yaml +0 -4
  79. package/skills/askr-auth-access/SKILL.md +0 -74
  80. package/skills/askr-auth-access/agents/openai.yaml +0 -4
  81. package/skills/askr-cli-vite/SKILL.md +0 -76
  82. package/skills/askr-cli-vite/agents/openai.yaml +0 -4
  83. package/skills/askr-dashboard-charts/SKILL.md +0 -99
  84. package/skills/askr-dashboard-charts/agents/openai.yaml +0 -4
  85. package/skills/askr-design-system/SKILL.md +0 -86
  86. package/skills/askr-design-system/agents/openai.yaml +0 -4
  87. package/skills/askr-env-config/SKILL.md +0 -74
  88. package/skills/askr-env-config/agents/openai.yaml +0 -4
  89. package/skills/askr-error-loading-empty/SKILL.md +0 -89
  90. package/skills/askr-error-loading-empty/agents/openai.yaml +0 -4
  91. package/skills/askr-file-upload-artifacts/SKILL.md +0 -77
  92. package/skills/askr-file-upload-artifacts/agents/openai.yaml +0 -4
  93. package/skills/askr-forms-tables-crud/SKILL.md +0 -98
  94. package/skills/askr-forms-tables-crud/agents/openai.yaml +0 -4
  95. package/skills/askr-mental-model/SKILL.md +0 -109
  96. package/skills/askr-mental-model/agents/openai.yaml +0 -4
  97. package/skills/askr-migration-react/SKILL.md +0 -81
  98. package/skills/askr-migration-react/agents/openai.yaml +0 -4
  99. package/skills/askr-observability-debugging/SKILL.md +0 -83
  100. package/skills/askr-observability-debugging/agents/openai.yaml +0 -4
  101. package/skills/askr-project-structure/SKILL.md +0 -79
  102. package/skills/askr-project-structure/agents/openai.yaml +0 -4
  103. package/skills/askr-query-mutation/SKILL.md +0 -115
  104. package/skills/askr-query-mutation/agents/openai.yaml +0 -4
  105. package/skills/askr-realtime-streaming/SKILL.md +0 -76
  106. package/skills/askr-realtime-streaming/agents/openai.yaml +0 -4
  107. package/skills/askr-resources-data/SKILL.md +0 -100
  108. package/skills/askr-resources-data/agents/openai.yaml +0 -4
  109. package/skills/askr-routing-layouts/SKILL.md +0 -107
  110. package/skills/askr-routing-layouts/agents/openai.yaml +0 -4
  111. package/skills/askr-runtime-reactivity/SKILL.md +0 -92
  112. package/skills/askr-runtime-reactivity/agents/openai.yaml +0 -4
  113. package/skills/askr-ssr-ssg/SKILL.md +0 -76
  114. package/skills/askr-ssr-ssg/agents/openai.yaml +0 -4
  115. package/skills/askr-testing-determinism/SKILL.md +0 -75
  116. package/skills/askr-testing-determinism/agents/openai.yaml +0 -4
  117. package/skills/askr-theming/SKILL.md +0 -86
  118. package/skills/askr-theming/agents/openai.yaml +0 -4
  119. package/skills/askr-ui-composition/SKILL.md +0 -92
  120. package/skills/askr-ui-composition/agents/openai.yaml +0 -4
  121. package/templates/full-stack/AGENTS.md +0 -11
  122. package/templates/full-stack/README.md +0 -17
  123. package/templates/full-stack/gitignore.template +0 -4
  124. package/templates/full-stack/index.html +0 -13
  125. package/templates/full-stack/package.json +0 -39
  126. package/templates/full-stack/server.ts +0 -9
  127. package/templates/full-stack/src/action-authorizations.ts +0 -10
  128. package/templates/full-stack/src/actions/create-message.ts +0 -10
  129. package/templates/full-stack/src/i18n.ts +0 -8
  130. package/templates/full-stack/src/main.tsx +0 -11
  131. package/templates/full-stack/src/pages/home.tsx +0 -25
  132. package/templates/full-stack/src/pages/layout.tsx +0 -43
  133. package/templates/full-stack/src/pages/not-found.tsx +0 -7
  134. package/templates/full-stack/src/routes.tsx +0 -19
  135. package/templates/full-stack/src/schemas.ts +0 -10
  136. package/templates/full-stack/src/server/action-registry.ts +0 -8
  137. package/templates/full-stack/src/server/actions/create-message.ts +0 -14
  138. package/templates/full-stack/src/server/app.ts +0 -76
  139. package/templates/full-stack/src/server/dependencies.ts +0 -55
  140. package/templates/full-stack/src/server/entry-server.ts +0 -8
  141. package/templates/full-stack/src/telemetry.ts +0 -3
  142. package/templates/full-stack/src/vite-server.d.ts +0 -5
  143. package/templates/full-stack/tests/actions/create-message.test.ts +0 -12
  144. package/templates/full-stack/tsconfig.json +0 -15
  145. package/templates/full-stack/vite.config.ts +0 -10
  146. package/templates/spa/AGENTS.md +0 -60
  147. package/templates/spa/README.md +0 -96
  148. package/templates/spa/gitignore.template +0 -16
  149. package/templates/spa/index.html +0 -13
  150. package/templates/spa/package.json +0 -35
  151. package/templates/spa/src/adapters/operations-client.ts +0 -95
  152. package/templates/spa/src/components/shared/metric-card.tsx +0 -27
  153. package/templates/spa/src/components/shared/status-badge.tsx +0 -24
  154. package/templates/spa/src/features/operations/operations.query.ts +0 -9
  155. package/templates/spa/src/main.tsx +0 -10
  156. package/templates/spa/src/pages/_layout.tsx +0 -9
  157. package/templates/spa/src/pages/_routes.tsx +0 -27
  158. package/templates/spa/src/pages/app/_layout.tsx +0 -94
  159. package/templates/spa/src/pages/app/_routes.tsx +0 -10
  160. package/templates/spa/src/pages/app/admin-home.tsx +0 -170
  161. package/templates/spa/src/pages/app/agent-runs.tsx +0 -93
  162. package/templates/spa/src/pages/app/settings.tsx +0 -91
  163. package/templates/spa/src/pages/auth/_layout.tsx +0 -38
  164. package/templates/spa/src/pages/auth/_routes.tsx +0 -6
  165. package/templates/spa/src/pages/auth/login.tsx +0 -63
  166. package/templates/spa/src/pages/not-found.tsx +0 -22
  167. package/templates/spa/src/pages/public/_layout.tsx +0 -47
  168. package/templates/spa/src/pages/public/_routes.tsx +0 -6
  169. package/templates/spa/src/pages/public/home.tsx +0 -143
  170. package/templates/spa/src/shared/format.ts +0 -12
  171. package/templates/spa/src/shared/navigation.ts +0 -15
  172. package/templates/spa/src/styles/components.css +0 -49
  173. package/templates/spa/src/styles/layout.css +0 -192
  174. package/templates/spa/src/styles/reset.css +0 -44
  175. package/templates/spa/src/styles/theme.css +0 -57
  176. package/templates/spa/src/styles/tokens.css +0 -20
  177. package/templates/spa/src/styles.css +0 -7
  178. package/templates/spa/src/styles.d.ts +0 -1
  179. package/templates/spa/tests/app.test.tsx +0 -37
  180. package/templates/spa/tests/components/shared.test.tsx +0 -12
  181. package/templates/spa/tests/resources.test.ts +0 -22
  182. package/templates/spa/tsconfig.json +0 -20
  183. package/templates/spa/tsconfig.node.json +0 -10
  184. package/templates/spa/vite.config.ts +0 -24
  185. package/templates/spa/vitest.config.ts +0 -17
  186. package/templates/ssg/AGENTS.md +0 -55
  187. package/templates/ssg/README.md +0 -39
  188. package/templates/ssg/gitignore.template +0 -17
  189. package/templates/ssg/index.html +0 -13
  190. package/templates/ssg/package.json +0 -35
  191. package/templates/ssg/src/app.tsx +0 -14
  192. package/templates/ssg/src/components/badge.tsx +0 -3
  193. package/templates/ssg/src/components/counter.tsx +0 -30
  194. package/templates/ssg/src/components/site-shell.tsx +0 -111
  195. package/templates/ssg/src/jsx.d.ts +0 -23
  196. package/templates/ssg/src/main.tsx +0 -8
  197. package/templates/ssg/src/pages/about.tsx +0 -82
  198. package/templates/ssg/src/pages/content.tsx +0 -63
  199. package/templates/ssg/src/pages/example.tsx +0 -97
  200. package/templates/ssg/src/pages/home.tsx +0 -51
  201. package/templates/ssg/src/resources/user.ts +0 -15
  202. package/templates/ssg/src/routes.tsx +0 -15
  203. package/templates/ssg/src/styles.css +0 -89
  204. package/templates/ssg/src/vite-env.d.ts +0 -5
  205. package/templates/ssg/ssg.config.ts +0 -34
  206. package/templates/ssg/tests/app.test.tsx +0 -19
  207. package/templates/ssg/tests/components/counter.test.tsx +0 -18
  208. package/templates/ssg/tests/resources.test.ts +0 -11
  209. package/templates/ssg/tests/ssg-config.test.ts +0 -11
  210. package/templates/ssg/tsconfig.json +0 -20
  211. package/templates/ssg/tsconfig.node.json +0 -10
  212. package/templates/ssg/vite.config.ts +0 -24
  213. package/templates/ssg/vitest.config.ts +0 -17
  214. package/templates/ssr/AGENTS.md +0 -28
  215. package/templates/ssr/README.md +0 -38
  216. package/templates/ssr/gitignore.template +0 -16
  217. package/templates/ssr/index.html +0 -13
  218. package/templates/ssr/package.json +0 -34
  219. package/templates/ssr/server.ts +0 -10
  220. package/templates/ssr/src/app.tsx +0 -21
  221. package/templates/ssr/src/components/counter.tsx +0 -26
  222. package/templates/ssr/src/entry-server.tsx +0 -12
  223. package/templates/ssr/src/main.tsx +0 -11
  224. package/templates/ssr/src/pages/about.tsx +0 -75
  225. package/templates/ssr/src/pages/example.tsx +0 -113
  226. package/templates/ssr/src/pages/home.tsx +0 -56
  227. package/templates/ssr/src/resources/user.ts +0 -15
  228. package/templates/ssr/src/routes.tsx +0 -13
  229. package/templates/ssr/src/styles.css +0 -148
  230. package/templates/ssr/src/vite-server.d.ts +0 -7
  231. package/templates/ssr/tests/app.test.tsx +0 -24
  232. package/templates/ssr/tests/components/counter.test.tsx +0 -13
  233. package/templates/ssr/tests/resources.test.ts +0 -11
  234. package/templates/ssr/tsconfig.json +0 -22
  235. package/templates/ssr/tsconfig.node.json +0 -10
  236. package/templates/ssr/tsconfig.server.json +0 -15
  237. package/templates/ssr/vite.config.ts +0 -25
  238. package/templates/ssr/vitest.config.ts +0 -13
  239. package/templates/startkit/AGENTS.md +0 -77
  240. package/templates/startkit/README.md +0 -192
  241. package/templates/startkit/gitignore.template +0 -16
  242. package/templates/startkit/index.html +0 -13
  243. package/templates/startkit/package.json +0 -35
  244. package/templates/startkit/src/components/app-header.tsx +0 -93
  245. package/templates/startkit/src/components/app-sidebar.tsx +0 -95
  246. package/templates/startkit/src/components/data-table.tsx +0 -80
  247. package/templates/startkit/src/components/empty-state.tsx +0 -13
  248. package/templates/startkit/src/components/page-header.tsx +0 -23
  249. package/templates/startkit/src/components/stat-card.tsx +0 -24
  250. package/templates/startkit/src/features/accounts/account-filters.tsx +0 -61
  251. package/templates/startkit/src/features/accounts/account-table.tsx +0 -79
  252. package/templates/startkit/src/lib/format.ts +0 -31
  253. package/templates/startkit/src/lib/mock-data.ts +0 -441
  254. package/templates/startkit/src/lib/routes.ts +0 -116
  255. package/templates/startkit/src/main.tsx +0 -12
  256. package/templates/startkit/src/pages/_layout.tsx +0 -56
  257. package/templates/startkit/src/pages/auth/_layout.tsx +0 -7
  258. package/templates/startkit/src/pages/auth/login.tsx +0 -129
  259. package/templates/startkit/src/pages/home.tsx +0 -83
  260. package/templates/startkit/src/pages/not-found.tsx +0 -24
  261. package/templates/startkit/src/pages/workspace/_layout.tsx +0 -17
  262. package/templates/startkit/src/pages/workspace/accounts/index.tsx +0 -217
  263. package/templates/startkit/src/pages/workspace/dashboard.tsx +0 -118
  264. package/templates/startkit/src/pages/workspace/settings.tsx +0 -218
  265. package/templates/startkit/src/router.tsx +0 -7
  266. package/templates/startkit/src/routes/auth-config.ts +0 -38
  267. package/templates/startkit/src/routes/auth.ts +0 -8
  268. package/templates/startkit/src/routes/index.ts +0 -28
  269. package/templates/startkit/src/routes/public.ts +0 -8
  270. package/templates/startkit/src/routes/workspace/accounts.ts +0 -8
  271. package/templates/startkit/src/routes/workspace/index.ts +0 -14
  272. package/templates/startkit/src/styles/components.css +0 -396
  273. package/templates/startkit/src/styles/layout.css +0 -192
  274. package/templates/startkit/src/styles/reset.css +0 -38
  275. package/templates/startkit/src/styles/theme.css +0 -76
  276. package/templates/startkit/src/styles/tokens.css +0 -67
  277. package/templates/startkit/src/styles.css +0 -7
  278. package/templates/startkit/src/toast.ts +0 -55
  279. package/templates/startkit/src/utils/join-classes.ts +0 -4
  280. package/templates/startkit/src/vite-env.d.ts +0 -5
  281. package/templates/startkit/tests/app.test.tsx +0 -32
  282. package/templates/startkit/tests/preferences.test.ts +0 -43
  283. package/templates/startkit/tests/resources.test.ts +0 -82
  284. package/templates/startkit/tsconfig.json +0 -20
  285. package/templates/startkit/tsconfig.node.json +0 -10
  286. package/templates/startkit/vite.config.ts +0 -32
  287. package/templates/startkit/vitest.config.ts +0 -13
@@ -1,56 +0,0 @@
1
- import '../styles.css';
2
- import {
3
- ToastHost,
4
- Toast,
5
- ToastClose,
6
- ToastDescription,
7
- ToastTitle,
8
- ToastViewport,
9
- } from '@askrjs/ui/toast';
10
- import {
11
- clearToast,
12
- bindToast,
13
- setToastOpen,
14
- toastMessage,
15
- toastOpen,
16
- } from '../toast';
17
- import { state } from '@askrjs/askr';
18
-
19
- export default function App({ children }: { children?: unknown }) {
20
- const [messageState, setMessageState] = state(toastMessage());
21
- const [openState, setOpenState] = state(toastOpen());
22
-
23
- bindToast({
24
- setMessage: setMessageState,
25
- setOpen: setOpenState,
26
- });
27
-
28
- const messageTitle = () => messageState()?.title ?? '';
29
- const messageDescription = () => messageState()?.description;
30
-
31
- return (
32
- <ToastHost duration={2400}>
33
- <div class="app-root">{children}</div>
34
-
35
- <ToastViewport class="app-toast-viewport" />
36
- {messageState() && (
37
- <Toast
38
- open={openState()}
39
- onOpenChange={(open) => {
40
- setToastOpen(open);
41
- if (!open) {
42
- clearToast();
43
- }
44
- }}
45
- class="app-toast"
46
- >
47
- <ToastTitle>{messageTitle()}</ToastTitle>
48
- {messageDescription() && (
49
- <ToastDescription>{messageDescription()}</ToastDescription>
50
- )}
51
- <ToastClose aria-label="Dismiss notification">Dismiss</ToastClose>
52
- </Toast>
53
- )}
54
- </ToastHost>
55
- );
56
- }
@@ -1,7 +0,0 @@
1
- export default function AuthLayout(props: { children?: unknown }) {
2
- return (
3
- <div class="auth-layout-shell">
4
- <div class="auth-layout-card">{props.children}</div>
5
- </div>
6
- );
7
- }
@@ -1,129 +0,0 @@
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
- }
@@ -1,83 +0,0 @@
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
- }
@@ -1,24 +0,0 @@
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
- }
@@ -1,17 +0,0 @@
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
- }
@@ -1,217 +0,0 @@
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
- }
@@ -1,118 +0,0 @@
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
- }