create-einja-app 0.2.17 → 0.2.19

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 (275) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.js +685 -1715
  3. package/dist/cli.js.map +1 -1
  4. package/package.json +2 -2
  5. package/templates/default/.claude/hooks/einja/playwright-resize.sh +12 -2
  6. package/templates/default/.claude/settings.json +16 -0
  7. package/templates/default/.cursor/commands/task-vibe-kanban-loop.md +107 -42
  8. package/templates/default/.env.develop +0 -4
  9. package/templates/default/.env.example +1 -0
  10. package/templates/default/.env.preview +0 -4
  11. package/templates/default/.env.staging +19 -0
  12. package/templates/default/.github/actions/ci/action.yml +39 -0
  13. package/templates/default/.github/actions/migrate/action.yml +39 -0
  14. package/templates/default/.github/actions/neon-export-env/action.yml +28 -0
  15. package/templates/default/.github/actions/setup/action.yml +20 -0
  16. package/templates/default/.github/workflows/claude.yml +1 -0
  17. package/templates/default/.github/workflows/{cleanup-neon-branches.yml → cleanup-pr-preview-db.yml} +28 -24
  18. package/templates/default/.github/workflows/cleanup-pr-preview-on-close.yml +50 -0
  19. package/templates/default/.github/workflows/deploy-pr-preview.yml +398 -0
  20. package/templates/default/.github/workflows/deploy-stable-branches.yml +259 -0
  21. package/templates/default/.github/workflows/release-create-einja-app.yml +95 -0
  22. package/templates/default/.mcp.json +29 -11
  23. package/templates/default/.serena/project.yml +4 -0
  24. package/templates/default/.vscode/settings.json +18 -0
  25. package/templates/default/CLAUDE.md +129 -353
  26. package/templates/default/README.md +5 -14
  27. package/templates/default/apps/admin/next.config.ts +11 -0
  28. package/templates/default/apps/admin/package.json +55 -0
  29. package/templates/default/apps/admin/postcss.config.cjs +5 -0
  30. package/templates/default/apps/admin/src/app/(auth)/forgot-password/page.tsx +97 -0
  31. package/templates/default/apps/admin/src/app/(auth)/layout.tsx +18 -0
  32. package/templates/default/apps/admin/src/app/(auth)/otp/page.tsx +121 -0
  33. package/templates/default/apps/admin/src/app/(auth)/sign-in/page.tsx +145 -0
  34. package/templates/default/apps/admin/src/app/(auth)/sign-up/page.tsx +199 -0
  35. package/templates/default/apps/admin/src/app/(errors)/401/page.tsx +27 -0
  36. package/templates/default/apps/admin/src/app/(errors)/403/page.tsx +28 -0
  37. package/templates/default/apps/admin/src/app/(errors)/500/page.tsx +29 -0
  38. package/templates/default/apps/admin/src/app/(errors)/layout.tsx +7 -0
  39. package/templates/default/apps/admin/src/app/(errors)/maintenance/page.tsx +25 -0
  40. package/templates/default/apps/admin/src/app/dashboard/_components/analytics-chart.tsx +68 -0
  41. package/templates/default/apps/admin/src/app/dashboard/_components/analytics.tsx +182 -0
  42. package/templates/default/apps/admin/src/app/dashboard/_components/dashboard-page.tsx +74 -0
  43. package/templates/default/apps/admin/src/app/dashboard/_components/metric-cards.tsx +49 -0
  44. package/templates/default/apps/admin/src/app/dashboard/_components/overview-chart.tsx +73 -0
  45. package/templates/default/apps/admin/src/app/dashboard/_components/recent-sales.tsx +75 -0
  46. package/templates/default/apps/admin/src/app/dashboard/apps/_components/apps-page.tsx +135 -0
  47. package/templates/default/apps/admin/src/app/dashboard/apps/page.tsx +10 -0
  48. package/templates/default/apps/admin/src/app/dashboard/chats/_components/chat-list.tsx +82 -0
  49. package/templates/default/apps/admin/src/app/dashboard/chats/_components/chat-messages.tsx +194 -0
  50. package/templates/default/apps/admin/src/app/dashboard/chats/_components/chats-page.tsx +99 -0
  51. package/templates/default/apps/admin/src/app/dashboard/chats/_components/new-chat.tsx +118 -0
  52. package/templates/default/apps/admin/src/app/dashboard/chats/page.tsx +10 -0
  53. package/templates/default/apps/admin/src/app/dashboard/layout.tsx +9 -0
  54. package/templates/default/apps/admin/src/app/dashboard/not-found.tsx +14 -0
  55. package/templates/default/apps/admin/src/app/dashboard/page.tsx +10 -0
  56. package/templates/default/apps/admin/src/app/dashboard/settings/_components/content-section.tsx +20 -0
  57. package/templates/default/apps/admin/src/app/dashboard/settings/_components/sidebar-nav.tsx +66 -0
  58. package/templates/default/apps/admin/src/app/dashboard/settings/account/page.tsx +173 -0
  59. package/templates/default/apps/admin/src/app/dashboard/settings/appearance/page.tsx +156 -0
  60. package/templates/default/apps/admin/src/app/dashboard/settings/display/page.tsx +125 -0
  61. package/templates/default/apps/admin/src/app/dashboard/settings/layout.tsx +30 -0
  62. package/templates/default/apps/admin/src/app/dashboard/settings/notifications/page.tsx +196 -0
  63. package/templates/default/apps/admin/src/app/dashboard/settings/page.tsx +5 -0
  64. package/templates/default/apps/admin/src/app/dashboard/settings/profile/page.tsx +176 -0
  65. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/data-table-bulk-actions.tsx +183 -0
  66. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/data-table-row-actions.tsx +79 -0
  67. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/tasks-columns.tsx +107 -0
  68. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/tasks-dialogs.tsx +71 -0
  69. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/tasks-import-dialog.tsx +106 -0
  70. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/tasks-multi-delete-dialog.tsx +90 -0
  71. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/tasks-mutate-drawer.tsx +207 -0
  72. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/tasks-page.tsx +31 -0
  73. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/tasks-primary-buttons.tsx +19 -0
  74. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/tasks-provider.tsx +37 -0
  75. package/templates/default/apps/admin/src/app/dashboard/tasks/_components/tasks-table.tsx +155 -0
  76. package/templates/default/apps/admin/src/app/dashboard/tasks/page.tsx +14 -0
  77. package/templates/default/apps/admin/src/app/dashboard/users/_components/data-table-bulk-actions.tsx +136 -0
  78. package/templates/default/apps/admin/src/app/dashboard/users/_components/data-table-row-actions.tsx +62 -0
  79. package/templates/default/apps/admin/src/app/dashboard/users/_components/users-action-dialog.tsx +297 -0
  80. package/templates/default/apps/admin/src/app/dashboard/users/_components/users-columns.tsx +121 -0
  81. package/templates/default/apps/admin/src/app/dashboard/users/_components/users-delete-dialog.tsx +72 -0
  82. package/templates/default/apps/admin/src/app/dashboard/users/_components/users-dialogs.tsx +49 -0
  83. package/templates/default/apps/admin/src/app/dashboard/users/_components/users-invite-dialog.tsx +139 -0
  84. package/templates/default/apps/admin/src/app/dashboard/users/_components/users-multi-delete-dialog.tsx +89 -0
  85. package/templates/default/apps/admin/src/app/dashboard/users/_components/users-page.tsx +30 -0
  86. package/templates/default/apps/admin/src/app/dashboard/users/_components/users-primary-buttons.tsx +19 -0
  87. package/templates/default/apps/admin/src/app/dashboard/users/_components/users-provider.tsx +35 -0
  88. package/templates/default/apps/admin/src/app/dashboard/users/_components/users-table.tsx +157 -0
  89. package/templates/default/apps/admin/src/app/dashboard/users/page.tsx +10 -0
  90. package/templates/default/apps/admin/src/app/globals.css +109 -0
  91. package/templates/default/apps/admin/src/app/layout.tsx +32 -0
  92. package/templates/default/apps/admin/src/app/not-found.tsx +14 -0
  93. package/templates/default/apps/admin/src/app/page.tsx +5 -0
  94. package/templates/default/apps/admin/src/components/layout/admin-layout.tsx +16 -0
  95. package/templates/default/apps/admin/src/components/layout/app-sidebar.tsx +52 -0
  96. package/templates/default/apps/admin/src/components/layout/nav-config.ts +131 -0
  97. package/templates/default/apps/admin/src/components/providers/theme-provider.tsx +10 -0
  98. package/templates/default/apps/admin/src/components/shared/long-text.tsx +78 -0
  99. package/templates/default/apps/admin/src/components/shared/search-input.tsx +16 -0
  100. package/templates/default/apps/admin/src/components/shared/select-dropdown.tsx +64 -0
  101. package/templates/default/apps/admin/src/data/apps.tsx +116 -0
  102. package/templates/default/apps/admin/src/data/chats.ts +114 -0
  103. package/templates/default/apps/admin/src/data/tasks.ts +114 -0
  104. package/templates/default/apps/admin/src/data/users.ts +90 -0
  105. package/templates/default/apps/admin/src/hooks/use-dialog-state.ts +17 -0
  106. package/templates/default/apps/admin/src/hooks/use-table-url-state.ts +243 -0
  107. package/templates/default/apps/admin/src/lib/show-submitted-data.tsx +12 -0
  108. package/templates/default/apps/admin/src/types/table.d.ts +9 -0
  109. package/templates/default/apps/admin/tsconfig.json +32 -0
  110. package/templates/default/apps/web/next.config.ts +1 -0
  111. package/templates/default/apps/web/package.json +0 -22
  112. package/templates/default/apps/web/postcss.config.cjs +0 -1
  113. package/templates/default/apps/web/src/app/(authenticated)/dashboard/page.tsx +4 -20
  114. package/templates/default/apps/web/src/app/(authenticated)/data/_components/UserTable.tsx +4 -4
  115. package/templates/default/apps/web/src/app/(authenticated)/data/page.tsx +1 -1
  116. package/templates/default/apps/web/src/app/(authenticated)/profile/page.tsx +1 -1
  117. package/templates/default/apps/web/src/app/error.tsx +8 -70
  118. package/templates/default/apps/web/src/app/global-error.tsx +8 -70
  119. package/templates/default/apps/web/src/app/globals.css +20 -0
  120. package/templates/default/apps/web/src/app/not-found.tsx +5 -39
  121. package/templates/default/apps/web/src/app/page.tsx +27 -203
  122. package/templates/default/apps/web/src/app/signin/page.tsx +27 -191
  123. package/templates/default/apps/web/src/app/signup/page.tsx +33 -240
  124. package/templates/default/apps/web/src/components/dashboard/dashboard-stats.tsx +11 -75
  125. package/templates/default/apps/web/src/components/shared/Sidebar.tsx +3 -3
  126. package/templates/default/apps/web/src/components/shared/header.tsx +17 -112
  127. package/templates/default/apps/web/tsconfig.json +0 -6
  128. package/templates/default/biome.json +1 -2
  129. package/templates/default/components.json +2 -2
  130. package/templates/default/docker-compose.yml +1 -1
  131. package/templates/default/gitignore +4 -0
  132. package/templates/default/package.json +1 -0
  133. package/templates/default/packages/admin-ui/catalog/catalog.css +54 -0
  134. package/templates/default/packages/admin-ui/catalog/catalog.tsx +401 -0
  135. package/templates/default/packages/admin-ui/catalog/index.html +12 -0
  136. package/templates/default/packages/admin-ui/catalog/main.tsx +9 -0
  137. package/templates/default/packages/admin-ui/components.json +21 -0
  138. package/templates/default/packages/admin-ui/package.json +105 -0
  139. package/templates/default/packages/admin-ui/src/command-menu/index.tsx +174 -0
  140. package/templates/default/packages/admin-ui/src/data-table/bulk-actions.tsx +215 -0
  141. package/templates/default/packages/admin-ui/src/data-table/column-header.tsx +73 -0
  142. package/templates/default/packages/admin-ui/src/data-table/data-table.tsx +127 -0
  143. package/templates/default/packages/admin-ui/src/data-table/faceted-filter.tsx +148 -0
  144. package/templates/default/packages/admin-ui/src/data-table/index.tsx +9 -0
  145. package/templates/default/packages/admin-ui/src/data-table/pagination.tsx +101 -0
  146. package/templates/default/packages/admin-ui/src/data-table/toolbar.tsx +87 -0
  147. package/templates/default/packages/admin-ui/src/data-table/view-options.tsx +57 -0
  148. package/templates/default/packages/admin-ui/src/hooks/use-mobile.tsx +23 -0
  149. package/templates/default/packages/admin-ui/src/layout/header.tsx +55 -0
  150. package/templates/default/packages/admin-ui/src/layout/index.ts +10 -0
  151. package/templates/default/packages/admin-ui/src/layout/main.tsx +23 -0
  152. package/templates/default/packages/admin-ui/src/layout/nav-group.tsx +111 -0
  153. package/templates/default/packages/admin-ui/src/layout/nav-user.tsx +114 -0
  154. package/templates/default/packages/admin-ui/src/layout/theme-switch.tsx +40 -0
  155. package/templates/default/packages/admin-ui/src/layout/types.ts +21 -0
  156. package/templates/default/packages/admin-ui/src/lib/utils.ts +6 -0
  157. package/templates/default/packages/admin-ui/src/styles/base.css +65 -0
  158. package/templates/default/packages/admin-ui/src/styles/tokens.css +91 -0
  159. package/templates/default/packages/admin-ui/src/tanstack-table.d.ts +10 -0
  160. package/templates/default/packages/admin-ui/src/ui/alert-dialog.tsx +157 -0
  161. package/templates/default/packages/admin-ui/src/ui/alert.tsx +66 -0
  162. package/templates/default/packages/admin-ui/src/ui/avatar.tsx +53 -0
  163. package/templates/default/packages/admin-ui/src/ui/badge.tsx +46 -0
  164. package/templates/default/packages/admin-ui/src/ui/breadcrumb.tsx +108 -0
  165. package/templates/default/packages/admin-ui/src/ui/button.tsx +59 -0
  166. package/templates/default/packages/admin-ui/src/ui/calendar.tsx +69 -0
  167. package/templates/default/packages/admin-ui/src/ui/card.tsx +92 -0
  168. package/templates/default/packages/admin-ui/src/ui/chart.tsx +345 -0
  169. package/templates/default/packages/admin-ui/src/ui/checkbox.tsx +32 -0
  170. package/templates/default/packages/admin-ui/src/ui/collapsible.tsx +27 -0
  171. package/templates/default/packages/admin-ui/src/ui/command.tsx +161 -0
  172. package/templates/default/packages/admin-ui/src/ui/confirm-dialog.tsx +72 -0
  173. package/templates/default/packages/admin-ui/src/ui/date-picker.tsx +53 -0
  174. package/templates/default/packages/admin-ui/src/ui/dialog.tsx +143 -0
  175. package/templates/default/packages/admin-ui/src/ui/dropdown-menu.tsx +257 -0
  176. package/templates/default/packages/admin-ui/src/ui/form.tsx +168 -0
  177. package/templates/default/packages/admin-ui/src/ui/input-otp.tsx +84 -0
  178. package/templates/default/packages/admin-ui/src/ui/input.tsx +21 -0
  179. package/templates/default/packages/admin-ui/src/ui/label.tsx +24 -0
  180. package/templates/default/packages/admin-ui/src/ui/pagination.tsx +126 -0
  181. package/templates/default/packages/admin-ui/src/ui/password-input.tsx +46 -0
  182. package/templates/default/packages/admin-ui/src/ui/popover.tsx +48 -0
  183. package/templates/default/packages/admin-ui/src/ui/progress.tsx +31 -0
  184. package/templates/default/packages/admin-ui/src/ui/radio-group.tsx +45 -0
  185. package/templates/default/packages/admin-ui/src/ui/scroll-area.tsx +52 -0
  186. package/templates/default/packages/admin-ui/src/ui/select.tsx +185 -0
  187. package/templates/default/packages/admin-ui/src/ui/separator.tsx +28 -0
  188. package/templates/default/packages/admin-ui/src/ui/sheet.tsx +149 -0
  189. package/templates/default/packages/admin-ui/src/ui/sidebar.tsx +728 -0
  190. package/templates/default/packages/admin-ui/src/ui/skeleton.tsx +13 -0
  191. package/templates/default/packages/admin-ui/src/ui/sonner.tsx +25 -0
  192. package/templates/default/packages/admin-ui/src/ui/switch.tsx +31 -0
  193. package/templates/default/packages/admin-ui/src/ui/table.tsx +116 -0
  194. package/templates/default/packages/admin-ui/src/ui/tabs.tsx +66 -0
  195. package/templates/default/packages/admin-ui/src/ui/textarea.tsx +18 -0
  196. package/templates/default/packages/admin-ui/src/ui/toggle-group.tsx +60 -0
  197. package/templates/default/packages/admin-ui/src/ui/toggle.tsx +44 -0
  198. package/templates/default/packages/admin-ui/src/ui/tooltip.tsx +61 -0
  199. package/templates/default/packages/admin-ui/tsconfig.json +8 -0
  200. package/templates/default/packages/admin-ui/vite.config.ts +11 -0
  201. package/templates/default/packages/config/package.json +0 -2
  202. package/templates/default/packages/server-core/package.json +1 -0
  203. package/templates/default/packages/ui/components.json +21 -0
  204. package/templates/default/packages/ui/package.json +42 -5
  205. package/templates/default/packages/ui/src/accordion.tsx +1 -1
  206. package/templates/default/packages/ui/src/alert-dialog.tsx +4 -4
  207. package/templates/default/packages/ui/src/alert.tsx +1 -1
  208. package/templates/default/packages/ui/src/avatar.tsx +1 -1
  209. package/templates/default/packages/ui/src/badge.tsx +1 -1
  210. package/templates/default/packages/ui/src/breadcrumb.tsx +1 -1
  211. package/templates/default/packages/ui/src/button.tsx +1 -1
  212. package/templates/default/packages/ui/src/card.tsx +1 -1
  213. package/templates/default/packages/ui/src/checkbox.tsx +1 -1
  214. package/templates/default/packages/ui/src/dialog.tsx +3 -3
  215. package/templates/default/packages/ui/src/drawer.tsx +3 -3
  216. package/templates/default/packages/ui/src/dropdown-menu.tsx +3 -3
  217. package/templates/default/packages/ui/src/form.tsx +2 -2
  218. package/templates/default/packages/ui/src/hover-card.tsx +2 -2
  219. package/templates/default/packages/ui/src/input.tsx +1 -1
  220. package/templates/default/packages/ui/src/label.tsx +1 -1
  221. package/templates/default/packages/ui/src/pagination.tsx +2 -2
  222. package/templates/default/packages/ui/src/popover.tsx +2 -2
  223. package/templates/default/packages/ui/src/progress.tsx +1 -1
  224. package/templates/default/packages/ui/src/select.tsx +2 -2
  225. package/templates/default/packages/ui/src/separator.tsx +1 -1
  226. package/templates/default/packages/ui/src/skeleton.tsx +1 -1
  227. package/templates/default/packages/ui/src/table.tsx +1 -1
  228. package/templates/default/packages/ui/src/tabs.tsx +1 -1
  229. package/templates/default/packages/ui/src/textarea.tsx +1 -1
  230. package/templates/default/packages/ui/src/tooltip.tsx +3 -3
  231. package/templates/default/packages/ui/src/typography.tsx +1 -1
  232. package/templates/default/packages/ui/tsconfig.json +1 -6
  233. package/templates/default/pnpm-lock.yaml +1319 -936
  234. package/templates/default/postcss.config.cjs +0 -1
  235. package/templates/default/turbo.json +11 -5
  236. package/templates/default/worktree.config.json +5 -0
  237. package/templates/default/.env.ci +0 -32
  238. package/templates/default/.github/workflows/ci.yml +0 -96
  239. package/templates/default/.github/workflows/preview-db.yml +0 -134
  240. package/templates/default/.playwright-mcp/dashboard.png +0 -0
  241. package/templates/default/.playwright-mcp/web-home.png +0 -0
  242. package/templates/default/apps/web/panda.config.ts +0 -114
  243. package/templates/default/apps/web/src/components/ui/accordion.tsx +0 -64
  244. package/templates/default/apps/web/src/components/ui/alert-dialog.tsx +0 -135
  245. package/templates/default/apps/web/src/components/ui/alert.tsx +0 -60
  246. package/templates/default/apps/web/src/components/ui/aspect-ratio.tsx +0 -9
  247. package/templates/default/apps/web/src/components/ui/avatar.tsx +0 -41
  248. package/templates/default/apps/web/src/components/ui/badge.tsx +0 -39
  249. package/templates/default/apps/web/src/components/ui/breadcrumb.tsx +0 -101
  250. package/templates/default/apps/web/src/components/ui/button.tsx +0 -56
  251. package/templates/default/apps/web/src/components/ui/card.tsx +0 -75
  252. package/templates/default/apps/web/src/components/ui/checkbox.tsx +0 -29
  253. package/templates/default/apps/web/src/components/ui/data-table.tsx +0 -189
  254. package/templates/default/apps/web/src/components/ui/dialog-hook.tsx +0 -210
  255. package/templates/default/apps/web/src/components/ui/dialog.tsx +0 -129
  256. package/templates/default/apps/web/src/components/ui/drawer.tsx +0 -124
  257. package/templates/default/apps/web/src/components/ui/dropdown-menu.tsx +0 -228
  258. package/templates/default/apps/web/src/components/ui/form.tsx +0 -152
  259. package/templates/default/apps/web/src/components/ui/hover-card.tsx +0 -38
  260. package/templates/default/apps/web/src/components/ui/input.tsx +0 -21
  261. package/templates/default/apps/web/src/components/ui/label.tsx +0 -21
  262. package/templates/default/apps/web/src/components/ui/pagination.tsx +0 -105
  263. package/templates/default/apps/web/src/components/ui/popover.tsx +0 -42
  264. package/templates/default/apps/web/src/components/ui/progress.tsx +0 -28
  265. package/templates/default/apps/web/src/components/ui/select.tsx +0 -170
  266. package/templates/default/apps/web/src/components/ui/separator.tsx +0 -28
  267. package/templates/default/apps/web/src/components/ui/skeleton.tsx +0 -13
  268. package/templates/default/apps/web/src/components/ui/sonner.tsx +0 -25
  269. package/templates/default/apps/web/src/components/ui/table.tsx +0 -92
  270. package/templates/default/apps/web/src/components/ui/tabs.tsx +0 -54
  271. package/templates/default/apps/web/src/components/ui/textarea.tsx +0 -18
  272. package/templates/default/apps/web/src/components/ui/tooltip.tsx +0 -57
  273. package/templates/default/apps/web/src/components/ui/typography.tsx +0 -158
  274. package/templates/default/packages/config/panda.config.ts +0 -114
  275. package/templates/default/panda.config.ts +0 -114
@@ -0,0 +1,243 @@
1
+ "use client";
2
+
3
+ import type { ColumnFiltersState, OnChangeFn, PaginationState } from "@tanstack/react-table";
4
+ import { useRouter, useSearchParams } from "next/navigation";
5
+ import { useCallback, useMemo, useState } from "react";
6
+
7
+ type SearchRecord = Record<string, unknown>;
8
+
9
+ type UseTableUrlStateParams = {
10
+ pagination?: {
11
+ pageKey?: string;
12
+ pageSizeKey?: string;
13
+ defaultPage?: number;
14
+ defaultPageSize?: number;
15
+ };
16
+ globalFilter?: {
17
+ enabled?: boolean;
18
+ key?: string;
19
+ trim?: boolean;
20
+ };
21
+ columnFilters?: Array<
22
+ | {
23
+ columnId: string;
24
+ searchKey: string;
25
+ type?: "string";
26
+ // Optional transformers for custom types
27
+ serialize?: (value: unknown) => unknown;
28
+ deserialize?: (value: unknown) => unknown;
29
+ }
30
+ | {
31
+ columnId: string;
32
+ searchKey: string;
33
+ type: "array";
34
+ serialize?: (value: unknown) => unknown;
35
+ deserialize?: (value: unknown) => unknown;
36
+ }
37
+ >;
38
+ };
39
+
40
+ type UseTableUrlStateReturn = {
41
+ // Global filter
42
+ globalFilter?: string;
43
+ onGlobalFilterChange?: OnChangeFn<string>;
44
+ // Column filters
45
+ columnFilters: ColumnFiltersState;
46
+ onColumnFiltersChange: OnChangeFn<ColumnFiltersState>;
47
+ // Pagination
48
+ pagination: PaginationState;
49
+ onPaginationChange: OnChangeFn<PaginationState>;
50
+ // Helpers
51
+ ensurePageInRange: (pageCount: number, opts?: { resetTo?: "first" | "last" }) => void;
52
+ };
53
+
54
+ export function useTableUrlState(params: UseTableUrlStateParams): UseTableUrlStateReturn {
55
+ const {
56
+ pagination: paginationCfg,
57
+ globalFilter: globalFilterCfg,
58
+ columnFilters: columnFiltersCfg = [],
59
+ } = params;
60
+
61
+ const searchParams = useSearchParams();
62
+ const router = useRouter();
63
+
64
+ const pageKey = paginationCfg?.pageKey ?? ("page" as string);
65
+ const pageSizeKey = paginationCfg?.pageSizeKey ?? ("pageSize" as string);
66
+ const defaultPage = paginationCfg?.defaultPage ?? 1;
67
+ const defaultPageSize = paginationCfg?.defaultPageSize ?? 10;
68
+
69
+ const globalFilterKey = globalFilterCfg?.key ?? ("filter" as string);
70
+ const globalFilterEnabled = globalFilterCfg?.enabled ?? true;
71
+ const trimGlobal = globalFilterCfg?.trim ?? true;
72
+
73
+ // Convert URLSearchParams to SearchRecord
74
+ const search = useMemo(() => {
75
+ const record: SearchRecord = {};
76
+ searchParams.forEach((value, key) => {
77
+ // Try to parse as number
78
+ const num = Number(value);
79
+ if (!Number.isNaN(num)) {
80
+ record[key] = num;
81
+ } else {
82
+ // Try to parse as JSON (for arrays)
83
+ try {
84
+ record[key] = JSON.parse(value);
85
+ } catch {
86
+ record[key] = value;
87
+ }
88
+ }
89
+ });
90
+ return record;
91
+ }, [searchParams]);
92
+
93
+ // Navigate helper
94
+ const navigate = useCallback(
95
+ (opts: {
96
+ search: true | SearchRecord | ((prev: SearchRecord) => Partial<SearchRecord> | SearchRecord);
97
+ replace?: boolean;
98
+ }) => {
99
+ const nextSearch = typeof opts.search === "function" ? opts.search(search) : opts.search;
100
+
101
+ if (nextSearch === true) return;
102
+
103
+ const params = new URLSearchParams();
104
+ Object.entries(nextSearch).forEach(([key, value]) => {
105
+ if (value !== undefined && value !== null) {
106
+ if (typeof value === "object") {
107
+ params.set(key, JSON.stringify(value));
108
+ } else {
109
+ params.set(key, String(value));
110
+ }
111
+ }
112
+ });
113
+
114
+ const url = params.toString() ? `?${params.toString()}` : "";
115
+ if (opts.replace) {
116
+ router.replace(url);
117
+ } else {
118
+ router.push(url);
119
+ }
120
+ },
121
+ [router, search]
122
+ );
123
+
124
+ // Build initial column filters from the current search params
125
+ const initialColumnFilters: ColumnFiltersState = useMemo(() => {
126
+ const collected: ColumnFiltersState = [];
127
+ for (const cfg of columnFiltersCfg) {
128
+ const raw = (search as SearchRecord)[cfg.searchKey];
129
+ const deserialize = cfg.deserialize ?? ((v: unknown) => v);
130
+ if (cfg.type === "string") {
131
+ const value = (deserialize(raw) as string) ?? "";
132
+ if (typeof value === "string" && value.trim() !== "") {
133
+ collected.push({ id: cfg.columnId, value });
134
+ }
135
+ } else {
136
+ // default to array type
137
+ const value = (deserialize(raw) as unknown[]) ?? [];
138
+ if (Array.isArray(value) && value.length > 0) {
139
+ collected.push({ id: cfg.columnId, value });
140
+ }
141
+ }
142
+ }
143
+ return collected;
144
+ }, [columnFiltersCfg, search]);
145
+
146
+ const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(initialColumnFilters);
147
+
148
+ const pagination: PaginationState = useMemo(() => {
149
+ const rawPage = (search as SearchRecord)[pageKey];
150
+ const rawPageSize = (search as SearchRecord)[pageSizeKey];
151
+ const pageNum = typeof rawPage === "number" ? rawPage : defaultPage;
152
+ const pageSizeNum = typeof rawPageSize === "number" ? rawPageSize : defaultPageSize;
153
+ return { pageIndex: Math.max(0, pageNum - 1), pageSize: pageSizeNum };
154
+ }, [search, pageKey, pageSizeKey, defaultPage, defaultPageSize]);
155
+
156
+ const onPaginationChange: OnChangeFn<PaginationState> = (updater) => {
157
+ const next = typeof updater === "function" ? updater(pagination) : updater;
158
+ const nextPage = next.pageIndex + 1;
159
+ const nextPageSize = next.pageSize;
160
+ navigate({
161
+ search: (prev) => ({
162
+ ...(prev as SearchRecord),
163
+ [pageKey]: nextPage <= defaultPage ? undefined : nextPage,
164
+ [pageSizeKey]: nextPageSize === defaultPageSize ? undefined : nextPageSize,
165
+ }),
166
+ });
167
+ };
168
+
169
+ const [globalFilter, setGlobalFilter] = useState<string | undefined>(() => {
170
+ if (!globalFilterEnabled) return undefined;
171
+ const raw = (search as SearchRecord)[globalFilterKey];
172
+ return typeof raw === "string" ? raw : "";
173
+ });
174
+
175
+ const onGlobalFilterChange: OnChangeFn<string> | undefined = globalFilterEnabled
176
+ ? (updater) => {
177
+ const next = typeof updater === "function" ? updater(globalFilter ?? "") : updater;
178
+ const value = trimGlobal ? next.trim() : next;
179
+ setGlobalFilter(value);
180
+ navigate({
181
+ search: (prev) => ({
182
+ ...(prev as SearchRecord),
183
+ [pageKey]: undefined,
184
+ [globalFilterKey]: value ? value : undefined,
185
+ }),
186
+ });
187
+ }
188
+ : undefined;
189
+
190
+ const onColumnFiltersChange: OnChangeFn<ColumnFiltersState> = (updater) => {
191
+ const next = typeof updater === "function" ? updater(columnFilters) : updater;
192
+ setColumnFilters(next);
193
+
194
+ const patch: Record<string, unknown> = {};
195
+
196
+ for (const cfg of columnFiltersCfg) {
197
+ const found = next.find((f) => f.id === cfg.columnId);
198
+ const serialize = cfg.serialize ?? ((v: unknown) => v);
199
+ if (cfg.type === "string") {
200
+ const value = typeof found?.value === "string" ? (found.value as string) : "";
201
+ patch[cfg.searchKey] = value.trim() !== "" ? serialize(value) : undefined;
202
+ } else {
203
+ const value = Array.isArray(found?.value) ? (found?.value as unknown[]) : [];
204
+ patch[cfg.searchKey] = value.length > 0 ? serialize(value) : undefined;
205
+ }
206
+ }
207
+
208
+ navigate({
209
+ search: (prev) => ({
210
+ ...(prev as SearchRecord),
211
+ [pageKey]: undefined,
212
+ ...patch,
213
+ }),
214
+ });
215
+ };
216
+
217
+ const ensurePageInRange = (
218
+ pageCount: number,
219
+ opts: { resetTo?: "first" | "last" } = { resetTo: "first" }
220
+ ) => {
221
+ const currentPage = (search as SearchRecord)[pageKey];
222
+ const pageNum = typeof currentPage === "number" ? currentPage : defaultPage;
223
+ if (pageCount > 0 && pageNum > pageCount) {
224
+ navigate({
225
+ replace: true,
226
+ search: (prev) => ({
227
+ ...(prev as SearchRecord),
228
+ [pageKey]: opts.resetTo === "last" ? pageCount : undefined,
229
+ }),
230
+ });
231
+ }
232
+ };
233
+
234
+ return {
235
+ globalFilter: globalFilterEnabled ? (globalFilter ?? "") : undefined,
236
+ onGlobalFilterChange,
237
+ columnFilters,
238
+ onColumnFiltersChange,
239
+ pagination,
240
+ onPaginationChange,
241
+ ensurePageInRange,
242
+ };
243
+ }
@@ -0,0 +1,12 @@
1
+ import { toast } from "sonner";
2
+
3
+ export function showSubmittedData(data: unknown, title = "You submitted the following values:") {
4
+ toast.message(title, {
5
+ description: (
6
+ // w-[340px]
7
+ <pre className="mt-2 w-full overflow-x-auto rounded-md bg-slate-950 p-4">
8
+ <code className="text-white">{JSON.stringify(data, null, 2)}</code>
9
+ </pre>
10
+ ),
11
+ });
12
+ }
@@ -0,0 +1,9 @@
1
+ import "@tanstack/react-table";
2
+
3
+ declare module "@tanstack/react-table" {
4
+ interface ColumnMeta<TData, TValue> {
5
+ className?: string;
6
+ thClassName?: string;
7
+ tdClassName?: string;
8
+ }
9
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "extends": "@repo/config/typescript",
3
+ "compilerOptions": {
4
+ "plugins": [
5
+ {
6
+ "name": "next"
7
+ }
8
+ ],
9
+ "paths": {
10
+ "@/*": [
11
+ "./src/*"
12
+ ],
13
+ "@admin/*": [
14
+ "./src/*",
15
+ "./*"
16
+ ]
17
+ }
18
+ },
19
+ "include": [
20
+ "next-env.d.ts",
21
+ "**/*.ts",
22
+ "**/*.tsx",
23
+ ".next/types/**/*.ts"
24
+ ],
25
+ "exclude": [
26
+ "node_modules",
27
+ "**/*.test.ts",
28
+ "**/*.test.tsx",
29
+ "**/*.spec.ts",
30
+ "**/*.spec.tsx"
31
+ ]
32
+ }
@@ -5,6 +5,7 @@ const nextConfig: NextConfig = {
5
5
  ignoreDuringBuilds: true,
6
6
  },
7
7
  output: "standalone",
8
+ transpilePackages: ["@repo/ui"],
8
9
  };
9
10
 
10
11
  export default nextConfig;
@@ -6,8 +6,6 @@
6
6
  "dev": "rm -rf .next && next dev --turbopack --port ${PORT_WEB:-3000}",
7
7
  "build": "next build",
8
8
  "start": "next start",
9
- "generate": "panda codegen",
10
- "panda": "panda codegen",
11
9
  "lint": "biome check .",
12
10
  "lint:fix": "biome check --write",
13
11
  "format": "biome format .",
@@ -23,28 +21,11 @@
23
21
  "@repo/server-core": "workspace:*",
24
22
  "@repo/ui": "workspace:*",
25
23
  "@hookform/resolvers": "^5.1.1",
26
- "@radix-ui/react-accordion": "^1.2.11",
27
- "@radix-ui/react-alert-dialog": "^1.1.14",
28
- "@radix-ui/react-aspect-ratio": "^1.1.7",
29
- "@radix-ui/react-avatar": "^1.1.10",
30
- "@radix-ui/react-checkbox": "^1.3.2",
31
- "@radix-ui/react-dialog": "^1.1.15",
32
- "@radix-ui/react-dropdown-menu": "^2.1.15",
33
- "@radix-ui/react-hover-card": "^1.1.14",
34
24
  "@radix-ui/react-icons": "^1.3.2",
35
- "@radix-ui/react-label": "^2.1.7",
36
- "@radix-ui/react-popover": "^1.1.14",
37
- "@radix-ui/react-progress": "^1.1.7",
38
- "@radix-ui/react-select": "^2.2.5",
39
- "@radix-ui/react-separator": "^1.1.7",
40
- "@radix-ui/react-slot": "^1.2.3",
41
- "@radix-ui/react-tabs": "^1.1.12",
42
- "@radix-ui/react-tooltip": "^1.2.7",
43
25
  "@tailwindcss/postcss": "^4.1.10",
44
26
  "@tanstack/react-query": "^5.81.5",
45
27
  "@tanstack/react-table": "^8.21.3",
46
28
  "bcryptjs": "^3.0.2",
47
- "class-variance-authority": "^0.7.1",
48
29
  "clsx": "^2.1.1",
49
30
  "lucide-react": "^0.523.0",
50
31
  "next": "15.3.3",
@@ -54,16 +35,13 @@
54
35
  "react": "^19.0.0",
55
36
  "react-dom": "^19.0.0",
56
37
  "react-hook-form": "^7.59.0",
57
- "sonner": "^2.0.5",
58
38
  "tailwind-merge": "^3.3.1",
59
39
  "tailwindcss": "^4.1.10",
60
- "vaul": "^1.1.2",
61
40
  "zod": "^3.25.67"
62
41
  },
63
42
  "devDependencies": {
64
43
  "@biomejs/biome": "1.9.4",
65
44
  "@repo/config": "workspace:*",
66
- "@pandacss/dev": "^0.53.7",
67
45
  "@testing-library/jest-dom": "^6.6.3",
68
46
  "@testing-library/react": "^16.3.0",
69
47
  "@types/bcryptjs": "^2.4.6",
@@ -1,6 +1,5 @@
1
1
  module.exports = {
2
2
  plugins: {
3
- "@pandacss/dev/postcss": {},
4
3
  "@tailwindcss/postcss": {},
5
4
  },
6
5
  };
@@ -1,30 +1,14 @@
1
1
  import { DashboardStats } from "@/components/dashboard/dashboard-stats";
2
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
3
- import { H1, P } from "@/components/ui/typography";
4
2
  import { auth } from "@/lib/auth";
5
- import { css } from "../../../../styled-system/css";
3
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "{{packageName}}/ui/card";
4
+ import { H1, P } from "{{packageName}}/ui/typography";
6
5
 
7
6
  export default async function DashboardPage() {
8
7
  const session = await auth();
9
8
 
10
9
  return (
11
- <div
12
- className={css({
13
- minHeight: "100vh",
14
- background: "linear-gradient(135deg, {colors.gray.50} 0%, {colors.blue.50} 100%)",
15
- })}
16
- >
17
- <main
18
- className={css({
19
- maxWidth: "7xl",
20
- margin: "0 auto",
21
- padding: {
22
- base: "1.5rem 1rem",
23
- md: "2rem 1.5rem",
24
- lg: "2.5rem 2rem",
25
- },
26
- })}
27
- >
10
+ <div className="min-h-screen bg-gradient-to-br from-gray-50 to-blue-50">
11
+ <main className="max-w-7xl mx-auto px-4 py-6 md:px-6 md:py-8 lg:px-8 lg:py-10">
28
12
  <div className="space-y-8">
29
13
  {/* ページタイトル */}
30
14
  <div className="space-y-2">
@@ -1,15 +1,15 @@
1
1
  "use client";
2
2
 
3
3
  import type { UserListItem } from "@/application/use-cases/UserUseCases";
4
- import { Badge } from "@/components/ui/badge";
5
- import { Button } from "@/components/ui/button";
6
- import { DataTable } from "@/components/ui/data-table";
4
+ import { Badge } from "{{packageName}}/ui/badge";
5
+ import { Button } from "{{packageName}}/ui/button";
6
+ import { DataTable } from "{{packageName}}/ui/data-table";
7
7
  import {
8
8
  DropdownMenu,
9
9
  DropdownMenuContent,
10
10
  DropdownMenuItem,
11
11
  DropdownMenuTrigger,
12
- } from "@/components/ui/dropdown-menu";
12
+ } from "{{packageName}}/ui/dropdown-menu";
13
13
  import type { ColumnDef } from "@tanstack/react-table";
14
14
  import { ArrowUpDown, Edit, Eye, MoreHorizontal, Trash2 } from "lucide-react";
15
15
 
@@ -1,6 +1,6 @@
1
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
2
1
  import { prefetchUsers } from "@/hooks/api/prefetch-users";
3
2
  import type { PaginatedUserList } from "@/shared/schemas/user";
3
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "{{packageName}}/ui/card";
4
4
  import { UserTableContainer } from "./_components/UserTableContainer";
5
5
 
6
6
  export default async function DataPage() {
@@ -1,5 +1,5 @@
1
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
2
1
  import { auth } from "@/lib/auth";
2
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "{{packageName}}/ui/card";
3
3
 
4
4
  export default async function ProfilePage() {
5
5
  const session = await auth();
@@ -1,8 +1,5 @@
1
1
  "use client";
2
2
 
3
- import { css } from "@/styled-system/css";
4
- import { flex } from "@/styled-system/patterns";
5
-
6
3
  type ErrorPageProps = {
7
4
  error: Error & { digest?: string };
8
5
  reset: () => void;
@@ -14,89 +11,30 @@ export default function ErrorPage({ error, reset }: ErrorPageProps) {
14
11
  };
15
12
 
16
13
  return (
17
- <div
18
- className={css({
19
- minH: "100vh",
20
- display: "flex",
21
- flexDir: "column",
22
- alignItems: "center",
23
- justifyContent: "center",
24
- p: "4",
25
- bg: "white",
26
- })}
27
- >
28
- <div
29
- className={css({
30
- textAlign: "center",
31
- })}
32
- >
33
- <h1 className={css({ mb: "4" })}>エラーが発生しました</h1>
34
- <p
35
- className={css({
36
- color: "gray.600",
37
- mb: "8",
38
- fontSize: "lg",
39
- })}
40
- >
14
+ <div className="min-h-screen flex flex-col items-center justify-center p-4 bg-white">
15
+ <div className="text-center">
16
+ <h1 className="mb-4">エラーが発生しました</h1>
17
+ <p className="text-gray-600 mb-8 text-lg">
41
18
  申し訳ありません。予期せぬエラーが発生しました。
42
19
  </p>
43
- <div className={flex({ gap: "4", justify: "center" })}>
20
+ <div className="flex gap-4 justify-center">
44
21
  <button
45
22
  type="button"
46
23
  onClick={reset}
47
- className={css({
48
- display: "inline-flex",
49
- alignItems: "center",
50
- justifyContent: "center",
51
- px: "6",
52
- py: "3",
53
- bg: "blue.500",
54
- color: "white",
55
- fontWeight: "semibold",
56
- rounded: "md",
57
- _hover: { bg: "blue.600" },
58
- _active: { bg: "blue.700" },
59
- transition: "all 0.2s",
60
- })}
24
+ className="inline-flex items-center justify-center px-6 py-3 bg-blue-500 text-white font-semibold rounded-md hover:bg-blue-600 active:bg-blue-700 transition-all duration-200"
61
25
  >
62
26
  もう一度試す
63
27
  </button>
64
28
  <button
65
29
  type="button"
66
30
  onClick={handleHomeClick}
67
- className={css({
68
- display: "inline-flex",
69
- alignItems: "center",
70
- justifyContent: "center",
71
- px: "6",
72
- py: "3",
73
- border: "1px solid",
74
- borderColor: "blue.500",
75
- color: "blue.500",
76
- fontWeight: "semibold",
77
- rounded: "md",
78
- _hover: { bg: "blue.50" },
79
- _active: { bg: "blue.100" },
80
- transition: "all 0.2s",
81
- })}
31
+ className="inline-flex items-center justify-center px-6 py-3 border border-blue-500 text-blue-500 font-semibold rounded-md hover:bg-blue-50 active:bg-blue-100 transition-all duration-200"
82
32
  >
83
33
  トップページへ戻る
84
34
  </button>
85
35
  </div>
86
36
  {process.env.NODE_ENV === "development" && (
87
- <pre
88
- className={css({
89
- mt: "8",
90
- p: "4",
91
- bg: "gray.100",
92
- rounded: "md",
93
- textAlign: "left",
94
- overflow: "auto",
95
- maxW: "full",
96
- fontFamily: "mono",
97
- fontSize: "sm",
98
- })}
99
- >
37
+ <pre className="mt-8 p-4 bg-gray-100 rounded-md text-left overflow-auto max-w-full font-mono text-sm">
100
38
  {error.message}
101
39
  </pre>
102
40
  )}
@@ -1,8 +1,5 @@
1
1
  "use client";
2
2
 
3
- import { css } from "@/styled-system/css";
4
- import { flex } from "@/styled-system/patterns";
5
-
6
3
  type GlobalErrorPageProps = {
7
4
  error: Error & { digest?: string };
8
5
  reset: () => void;
@@ -16,89 +13,30 @@ export default function GlobalError({ error, reset }: GlobalErrorPageProps) {
16
13
  return (
17
14
  <html lang="ja">
18
15
  <body>
19
- <div
20
- className={css({
21
- minH: "100vh",
22
- display: "flex",
23
- flexDir: "column",
24
- alignItems: "center",
25
- justifyContent: "center",
26
- p: "4",
27
- bg: "gray.50",
28
- })}
29
- >
30
- <div
31
- className={css({
32
- textAlign: "center",
33
- })}
34
- >
35
- <h1 className={css({ mb: "4" })}>システムエラー</h1>
36
- <p
37
- className={css({
38
- color: "gray.600",
39
- mb: "8",
40
- fontSize: "lg",
41
- })}
42
- >
16
+ <div className="min-h-screen flex flex-col items-center justify-center p-4 bg-gray-50">
17
+ <div className="text-center">
18
+ <h1 className="mb-4">システムエラー</h1>
19
+ <p className="text-gray-600 mb-8 text-lg">
43
20
  申し訳ありません。システムエラーが発生しました。
44
21
  </p>
45
- <div className={flex({ gap: "4", justify: "center" })}>
22
+ <div className="flex gap-4 justify-center">
46
23
  <button
47
24
  type="button"
48
25
  onClick={reset}
49
- className={css({
50
- display: "inline-flex",
51
- alignItems: "center",
52
- justifyContent: "center",
53
- px: "6",
54
- py: "3",
55
- bg: "blue.500",
56
- color: "white",
57
- fontWeight: "semibold",
58
- rounded: "md",
59
- _hover: { bg: "blue.600" },
60
- _active: { bg: "blue.700" },
61
- transition: "all 0.2s",
62
- })}
26
+ className="inline-flex items-center justify-center px-6 py-3 bg-blue-500 text-white font-semibold rounded-md hover:bg-blue-600 active:bg-blue-700 transition-all duration-200"
63
27
  >
64
28
  もう一度試す
65
29
  </button>
66
30
  <button
67
31
  type="button"
68
32
  onClick={handleHomeClick}
69
- className={css({
70
- display: "inline-flex",
71
- alignItems: "center",
72
- justifyContent: "center",
73
- px: "6",
74
- py: "3",
75
- border: "1px solid",
76
- borderColor: "blue.500",
77
- color: "blue.500",
78
- fontWeight: "semibold",
79
- rounded: "md",
80
- _hover: { bg: "blue.50" },
81
- _active: { bg: "blue.100" },
82
- transition: "all 0.2s",
83
- })}
33
+ className="inline-flex items-center justify-center px-6 py-3 border border-blue-500 text-blue-500 font-semibold rounded-md hover:bg-blue-50 active:bg-blue-100 transition-all duration-200"
84
34
  >
85
35
  トップページへ戻る
86
36
  </button>
87
37
  </div>
88
38
  {process.env.NODE_ENV === "development" && (
89
- <pre
90
- className={css({
91
- mt: "8",
92
- p: "4",
93
- bg: "gray.100",
94
- rounded: "md",
95
- textAlign: "left",
96
- overflow: "auto",
97
- maxW: "full",
98
- fontFamily: "mono",
99
- fontSize: "sm",
100
- })}
101
- >
39
+ <pre className="mt-8 p-4 bg-gray-100 rounded-md text-left overflow-auto max-w-full font-mono text-sm">
102
40
  {error.message}
103
41
  </pre>
104
42
  )}