create-einja-app 0.1.1

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 (235) hide show
  1. package/README.md +307 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +1041 -0
  4. package/dist/cli.js.map +1 -0
  5. package/package.json +62 -0
  6. package/templates/turborepo-pandacss/.biomeignore +15 -0
  7. package/templates/turborepo-pandacss/.claude/hooks/einja/biome-format.sh +49 -0
  8. package/templates/turborepo-pandacss/.claude/hooks/einja/design-doc-check.sh +61 -0
  9. package/templates/turborepo-pandacss/.claude/hooks/einja/detect-secrets.sh +62 -0
  10. package/templates/turborepo-pandacss/.claude/hooks/einja/large-file-warning.sh +42 -0
  11. package/templates/turborepo-pandacss/.claude/hooks/einja/playwright-resize.sh +36 -0
  12. package/templates/turborepo-pandacss/.claude/hooks/einja/typecheck.sh +37 -0
  13. package/templates/turborepo-pandacss/.claude/hooks/einja/unset-volta-recursion.sh +32 -0
  14. package/templates/turborepo-pandacss/.claude/hooks/einja/validate-git-commit.sh +239 -0
  15. package/templates/turborepo-pandacss/.claude/hooks/einja/warn-index-ts.sh +34 -0
  16. package/templates/turborepo-pandacss/.claude/hooks/einja/warn-relative-import.sh +48 -0
  17. package/templates/turborepo-pandacss/.claude/settings.json +174 -0
  18. package/templates/turborepo-pandacss/.claude/skills/create-einja-app-release/SKILL.md +186 -0
  19. package/templates/turborepo-pandacss/.claude/skills/dev-cli-release/SKILL.md +173 -0
  20. package/templates/turborepo-pandacss/.cursor/commands/spec-create.md +227 -0
  21. package/templates/turborepo-pandacss/.cursor/commands/start-dev.md +98 -0
  22. package/templates/turborepo-pandacss/.cursor/commands/task-exec.md +287 -0
  23. package/templates/turborepo-pandacss/.cursor/commands/task-vibe-kanban-loop.md +532 -0
  24. package/templates/turborepo-pandacss/.cursor/commands/update-docs-by-task-specs.md +448 -0
  25. package/templates/turborepo-pandacss/.cursor/mcp.json +45 -0
  26. package/templates/turborepo-pandacss/.cursor/rules/api-rules.mdc +171 -0
  27. package/templates/turborepo-pandacss/.cursor/rules/api-test-rules.mdc +181 -0
  28. package/templates/turborepo-pandacss/.cursor/rules/base-code.mdc +70 -0
  29. package/templates/turborepo-pandacss/.cursor/rules/base-commit-rules.mdc +174 -0
  30. package/templates/turborepo-pandacss/.cursor/rules/base-design.mdc +12 -0
  31. package/templates/turborepo-pandacss/.cursor/rules/base-rules.mdc +231 -0
  32. package/templates/turborepo-pandacss/.cursor/rules/error-handling-rules.mdc +188 -0
  33. package/templates/turborepo-pandacss/.cursor/rules/refactor-rules.mdc +93 -0
  34. package/templates/turborepo-pandacss/.dockerignore +126 -0
  35. package/templates/turborepo-pandacss/.einja-sync.json +35 -0
  36. package/templates/turborepo-pandacss/.env.ci +25 -0
  37. package/templates/turborepo-pandacss/.env.example +35 -0
  38. package/templates/turborepo-pandacss/.env.personal.example +27 -0
  39. package/templates/turborepo-pandacss/.envrc +4 -0
  40. package/templates/turborepo-pandacss/.gitattributes +5 -0
  41. package/templates/turborepo-pandacss/.husky/pre-commit +1 -0
  42. package/templates/turborepo-pandacss/.lintstagedrc.js +24 -0
  43. package/templates/turborepo-pandacss/.mcp.json +45 -0
  44. package/templates/turborepo-pandacss/.node-version +1 -0
  45. package/templates/turborepo-pandacss/.templateignore +60 -0
  46. package/templates/turborepo-pandacss/.vscode/extensions.json +3 -0
  47. package/templates/turborepo-pandacss/CLAUDE.md +415 -0
  48. package/templates/turborepo-pandacss/README.md +322 -0
  49. package/templates/turborepo-pandacss/apps/web/middleware.ts +28 -0
  50. package/templates/turborepo-pandacss/apps/web/next.config.ts +10 -0
  51. package/templates/turborepo-pandacss/apps/web/package.json +80 -0
  52. package/templates/turborepo-pandacss/apps/web/panda.config.ts +114 -0
  53. package/templates/turborepo-pandacss/apps/web/postcss.config.cjs +6 -0
  54. package/templates/turborepo-pandacss/apps/web/public/file.svg +1 -0
  55. package/templates/turborepo-pandacss/apps/web/public/globe.svg +1 -0
  56. package/templates/turborepo-pandacss/apps/web/public/next.svg +1 -0
  57. package/templates/turborepo-pandacss/apps/web/public/vercel.svg +1 -0
  58. package/templates/turborepo-pandacss/apps/web/public/window.svg +1 -0
  59. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/dashboard/page.tsx +79 -0
  60. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/data/_components/UserTable.tsx +203 -0
  61. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/data/page.tsx +57 -0
  62. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/layout-client.tsx +31 -0
  63. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/layout.tsx +17 -0
  64. package/templates/turborepo-pandacss/apps/web/src/app/(authenticated)/profile/page.tsx +59 -0
  65. package/templates/turborepo-pandacss/apps/web/src/app/api/auth/[...nextauth]/route.ts +3 -0
  66. package/templates/turborepo-pandacss/apps/web/src/app/api/auth/signup/route.ts +70 -0
  67. package/templates/turborepo-pandacss/apps/web/src/app/error.tsx +106 -0
  68. package/templates/turborepo-pandacss/apps/web/src/app/favicon.ico +0 -0
  69. package/templates/turborepo-pandacss/apps/web/src/app/global-error.tsx +110 -0
  70. package/templates/turborepo-pandacss/apps/web/src/app/globals.css +121 -0
  71. package/templates/turborepo-pandacss/apps/web/src/app/layout.tsx +28 -0
  72. package/templates/turborepo-pandacss/apps/web/src/app/not-found.tsx +54 -0
  73. package/templates/turborepo-pandacss/apps/web/src/app/page.module.css +165 -0
  74. package/templates/turborepo-pandacss/apps/web/src/app/page.test.tsx +52 -0
  75. package/templates/turborepo-pandacss/apps/web/src/app/page.tsx +284 -0
  76. package/templates/turborepo-pandacss/apps/web/src/app/signin/page.tsx +296 -0
  77. package/templates/turborepo-pandacss/apps/web/src/app/signup/page.tsx +395 -0
  78. package/templates/turborepo-pandacss/apps/web/src/application/use-cases/UserUseCases.test.ts +229 -0
  79. package/templates/turborepo-pandacss/apps/web/src/application/use-cases/UserUseCases.ts +115 -0
  80. package/templates/turborepo-pandacss/apps/web/src/components/auth/login-button.tsx +35 -0
  81. package/templates/turborepo-pandacss/apps/web/src/components/auth/logout-button.tsx +24 -0
  82. package/templates/turborepo-pandacss/apps/web/src/components/auth/user-avatar.test.tsx +68 -0
  83. package/templates/turborepo-pandacss/apps/web/src/components/auth/user-avatar.tsx +43 -0
  84. package/templates/turborepo-pandacss/apps/web/src/components/dashboard/dashboard-stats.tsx +128 -0
  85. package/templates/turborepo-pandacss/apps/web/src/components/providers/query-provider.tsx +30 -0
  86. package/templates/turborepo-pandacss/apps/web/src/components/providers/session-provider.tsx +12 -0
  87. package/templates/turborepo-pandacss/apps/web/src/components/shared/Sidebar.tsx +175 -0
  88. package/templates/turborepo-pandacss/apps/web/src/components/shared/header.tsx +166 -0
  89. package/templates/turborepo-pandacss/apps/web/src/components/ui/accordion.tsx +64 -0
  90. package/templates/turborepo-pandacss/apps/web/src/components/ui/alert-dialog.tsx +135 -0
  91. package/templates/turborepo-pandacss/apps/web/src/components/ui/alert.tsx +60 -0
  92. package/templates/turborepo-pandacss/apps/web/src/components/ui/aspect-ratio.tsx +9 -0
  93. package/templates/turborepo-pandacss/apps/web/src/components/ui/avatar.tsx +41 -0
  94. package/templates/turborepo-pandacss/apps/web/src/components/ui/badge.tsx +39 -0
  95. package/templates/turborepo-pandacss/apps/web/src/components/ui/breadcrumb.tsx +101 -0
  96. package/templates/turborepo-pandacss/apps/web/src/components/ui/button.tsx +56 -0
  97. package/templates/turborepo-pandacss/apps/web/src/components/ui/card.tsx +75 -0
  98. package/templates/turborepo-pandacss/apps/web/src/components/ui/checkbox.tsx +29 -0
  99. package/templates/turborepo-pandacss/apps/web/src/components/ui/data-table.tsx +189 -0
  100. package/templates/turborepo-pandacss/apps/web/src/components/ui/dialog-hook.tsx +210 -0
  101. package/templates/turborepo-pandacss/apps/web/src/components/ui/dialog.tsx +129 -0
  102. package/templates/turborepo-pandacss/apps/web/src/components/ui/drawer.tsx +124 -0
  103. package/templates/turborepo-pandacss/apps/web/src/components/ui/dropdown-menu.tsx +228 -0
  104. package/templates/turborepo-pandacss/apps/web/src/components/ui/form.tsx +152 -0
  105. package/templates/turborepo-pandacss/apps/web/src/components/ui/hover-card.tsx +38 -0
  106. package/templates/turborepo-pandacss/apps/web/src/components/ui/input.tsx +21 -0
  107. package/templates/turborepo-pandacss/apps/web/src/components/ui/label.tsx +21 -0
  108. package/templates/turborepo-pandacss/apps/web/src/components/ui/pagination.tsx +105 -0
  109. package/templates/turborepo-pandacss/apps/web/src/components/ui/popover.tsx +42 -0
  110. package/templates/turborepo-pandacss/apps/web/src/components/ui/progress.tsx +28 -0
  111. package/templates/turborepo-pandacss/apps/web/src/components/ui/select.tsx +170 -0
  112. package/templates/turborepo-pandacss/apps/web/src/components/ui/separator.tsx +28 -0
  113. package/templates/turborepo-pandacss/apps/web/src/components/ui/skeleton.tsx +13 -0
  114. package/templates/turborepo-pandacss/apps/web/src/components/ui/sonner.tsx +25 -0
  115. package/templates/turborepo-pandacss/apps/web/src/components/ui/table.tsx +92 -0
  116. package/templates/turborepo-pandacss/apps/web/src/components/ui/tabs.tsx +54 -0
  117. package/templates/turborepo-pandacss/apps/web/src/components/ui/textarea.tsx +18 -0
  118. package/templates/turborepo-pandacss/apps/web/src/components/ui/tooltip.tsx +57 -0
  119. package/templates/turborepo-pandacss/apps/web/src/components/ui/typography.tsx +158 -0
  120. package/templates/turborepo-pandacss/apps/web/src/lib/auth/guard.ts +36 -0
  121. package/templates/turborepo-pandacss/apps/web/src/lib/auth/index.ts +22 -0
  122. package/templates/turborepo-pandacss/apps/web/src/lib/prisma.ts +3 -0
  123. package/templates/turborepo-pandacss/apps/web/src/lib/utils.ts +6 -0
  124. package/templates/turborepo-pandacss/apps/web/test/globals.d.ts +1 -0
  125. package/templates/turborepo-pandacss/apps/web/test/matchers.d.ts +1 -0
  126. package/templates/turborepo-pandacss/apps/web/test/setup.ts +22 -0
  127. package/templates/turborepo-pandacss/apps/web/tsconfig.json +37 -0
  128. package/templates/turborepo-pandacss/apps/web/vitest.config.ts +20 -0
  129. package/templates/turborepo-pandacss/apps/web/vitest.d.ts +2 -0
  130. package/templates/turborepo-pandacss/biome.json +60 -0
  131. package/templates/turborepo-pandacss/components.json +21 -0
  132. package/templates/turborepo-pandacss/docker-compose.yml +27 -0
  133. package/templates/turborepo-pandacss/middleware.ts +32 -0
  134. package/templates/turborepo-pandacss/next.config.ts +10 -0
  135. package/templates/turborepo-pandacss/package-lock.json +9346 -0
  136. package/templates/turborepo-pandacss/package.json +64 -0
  137. package/templates/turborepo-pandacss/packages/config/package.json +41 -0
  138. package/templates/turborepo-pandacss/packages/config/panda.config.ts +114 -0
  139. package/templates/turborepo-pandacss/packages/config/src/index.ts +24 -0
  140. package/templates/turborepo-pandacss/packages/config/src/worktree-config-loader.ts +129 -0
  141. package/templates/turborepo-pandacss/packages/config/src/worktree-config.ts +75 -0
  142. package/templates/turborepo-pandacss/packages/config/tsconfig.build.json +19 -0
  143. package/templates/turborepo-pandacss/packages/config/tsconfig.json +24 -0
  144. package/templates/turborepo-pandacss/packages/config/typescript/base.json +19 -0
  145. package/templates/turborepo-pandacss/packages/front-core/package.json +24 -0
  146. package/templates/turborepo-pandacss/packages/front-core/src/auth/config.ts +84 -0
  147. package/templates/turborepo-pandacss/packages/front-core/src/auth/index.ts +5 -0
  148. package/templates/turborepo-pandacss/packages/front-core/src/auth/types/next-auth.d.ts +20 -0
  149. package/templates/turborepo-pandacss/packages/front-core/src/auth/utils.ts +29 -0
  150. package/templates/turborepo-pandacss/packages/front-core/src/context/index.ts +2 -0
  151. package/templates/turborepo-pandacss/packages/front-core/src/hooks/index.ts +2 -0
  152. package/templates/turborepo-pandacss/packages/front-core/src/index.ts +4 -0
  153. package/templates/turborepo-pandacss/packages/front-core/src/utils/index.ts +2 -0
  154. package/templates/turborepo-pandacss/packages/front-core/tsconfig.json +14 -0
  155. package/templates/turborepo-pandacss/packages/server-core/package.json +32 -0
  156. package/templates/turborepo-pandacss/packages/server-core/prisma/schema.prisma +102 -0
  157. package/templates/turborepo-pandacss/packages/server-core/prisma/seed.ts +67 -0
  158. package/templates/turborepo-pandacss/packages/server-core/prisma.config.ts +8 -0
  159. package/templates/turborepo-pandacss/packages/server-core/src/__generated__/fabbrica/index.d.ts +270 -0
  160. package/templates/turborepo-pandacss/packages/server-core/src/__generated__/fabbrica/index.js +484 -0
  161. package/templates/turborepo-pandacss/packages/server-core/src/core/result.test.ts +78 -0
  162. package/templates/turborepo-pandacss/packages/server-core/src/core/result.ts +53 -0
  163. package/templates/turborepo-pandacss/packages/server-core/src/domain/.gitkeep +0 -0
  164. package/templates/turborepo-pandacss/packages/server-core/src/domain/entities/User.test.ts +232 -0
  165. package/templates/turborepo-pandacss/packages/server-core/src/domain/entities/User.ts +105 -0
  166. package/templates/turborepo-pandacss/packages/server-core/src/domain/repository-interfaces/IUserRepository.ts +101 -0
  167. package/templates/turborepo-pandacss/packages/server-core/src/infrastructure/database/client.ts +15 -0
  168. package/templates/turborepo-pandacss/packages/server-core/src/infrastructure/database/mappers/UserMapper.test.ts +278 -0
  169. package/templates/turborepo-pandacss/packages/server-core/src/infrastructure/database/mappers/UserMapper.ts +103 -0
  170. package/templates/turborepo-pandacss/packages/server-core/src/infrastructure/database/repositories/UserRepository.test.ts +317 -0
  171. package/templates/turborepo-pandacss/packages/server-core/src/infrastructure/database/repositories/UserRepository.ts +169 -0
  172. package/templates/turborepo-pandacss/packages/server-core/src/testing/factories/index.ts +22 -0
  173. package/templates/turborepo-pandacss/packages/server-core/src/testing/factories/user.factory.ts +123 -0
  174. package/templates/turborepo-pandacss/packages/server-core/src/testing/fixtures/users.ts +92 -0
  175. package/templates/turborepo-pandacss/packages/server-core/src/testing/helpers/date.ts +49 -0
  176. package/templates/turborepo-pandacss/packages/server-core/src/testing/helpers/password.ts +50 -0
  177. package/templates/turborepo-pandacss/packages/server-core/src/testing/index.ts +26 -0
  178. package/templates/turborepo-pandacss/packages/server-core/tsconfig.json +14 -0
  179. package/templates/turborepo-pandacss/packages/server-core/vitest.config.ts +15 -0
  180. package/templates/turborepo-pandacss/packages/ui/package.json +37 -0
  181. package/templates/turborepo-pandacss/packages/ui/src/accordion.tsx +66 -0
  182. package/templates/turborepo-pandacss/packages/ui/src/alert-dialog.tsx +157 -0
  183. package/templates/turborepo-pandacss/packages/ui/src/alert.tsx +66 -0
  184. package/templates/turborepo-pandacss/packages/ui/src/aspect-ratio.tsx +11 -0
  185. package/templates/turborepo-pandacss/packages/ui/src/avatar.tsx +53 -0
  186. package/templates/turborepo-pandacss/packages/ui/src/badge.tsx +46 -0
  187. package/templates/turborepo-pandacss/packages/ui/src/breadcrumb.tsx +108 -0
  188. package/templates/turborepo-pandacss/packages/ui/src/button.tsx +59 -0
  189. package/templates/turborepo-pandacss/packages/ui/src/card.tsx +92 -0
  190. package/templates/turborepo-pandacss/packages/ui/src/checkbox.tsx +32 -0
  191. package/templates/turborepo-pandacss/packages/ui/src/data-table.tsx +216 -0
  192. package/templates/turborepo-pandacss/packages/ui/src/dialog-hook.tsx +226 -0
  193. package/templates/turborepo-pandacss/packages/ui/src/dialog.tsx +143 -0
  194. package/templates/turborepo-pandacss/packages/ui/src/drawer.tsx +135 -0
  195. package/templates/turborepo-pandacss/packages/ui/src/dropdown-menu.tsx +257 -0
  196. package/templates/turborepo-pandacss/packages/ui/src/form.tsx +168 -0
  197. package/templates/turborepo-pandacss/packages/ui/src/hover-card.tsx +44 -0
  198. package/templates/turborepo-pandacss/packages/ui/src/input.tsx +21 -0
  199. package/templates/turborepo-pandacss/packages/ui/src/label.tsx +24 -0
  200. package/templates/turborepo-pandacss/packages/ui/src/lib/utils.ts +6 -0
  201. package/templates/turborepo-pandacss/packages/ui/src/pagination.tsx +126 -0
  202. package/templates/turborepo-pandacss/packages/ui/src/popover.tsx +48 -0
  203. package/templates/turborepo-pandacss/packages/ui/src/progress.tsx +31 -0
  204. package/templates/turborepo-pandacss/packages/ui/src/select.tsx +185 -0
  205. package/templates/turborepo-pandacss/packages/ui/src/separator.tsx +28 -0
  206. package/templates/turborepo-pandacss/packages/ui/src/skeleton.tsx +13 -0
  207. package/templates/turborepo-pandacss/packages/ui/src/sonner.tsx +25 -0
  208. package/templates/turborepo-pandacss/packages/ui/src/table.tsx +116 -0
  209. package/templates/turborepo-pandacss/packages/ui/src/tabs.tsx +66 -0
  210. package/templates/turborepo-pandacss/packages/ui/src/textarea.tsx +18 -0
  211. package/templates/turborepo-pandacss/packages/ui/src/tooltip.tsx +61 -0
  212. package/templates/turborepo-pandacss/packages/ui/src/typography.tsx +187 -0
  213. package/templates/turborepo-pandacss/packages/ui/tsconfig.json +20 -0
  214. package/templates/turborepo-pandacss/panda.config.ts +114 -0
  215. package/templates/turborepo-pandacss/pnpm-lock.yaml +9032 -0
  216. package/templates/turborepo-pandacss/pnpm-workspace.yaml +11 -0
  217. package/templates/turborepo-pandacss/postcss.config.cjs +6 -0
  218. package/templates/turborepo-pandacss/prisma/schema.prisma +82 -0
  219. package/templates/turborepo-pandacss/public/file.svg +1 -0
  220. package/templates/turborepo-pandacss/public/globe.svg +1 -0
  221. package/templates/turborepo-pandacss/public/next.svg +1 -0
  222. package/templates/turborepo-pandacss/public/vercel.svg +1 -0
  223. package/templates/turborepo-pandacss/public/window.svg +1 -0
  224. package/templates/turborepo-pandacss/scripts/cli-template-update.ts +387 -0
  225. package/templates/turborepo-pandacss/scripts/env-show.ts +129 -0
  226. package/templates/turborepo-pandacss/scripts/env.ts +555 -0
  227. package/templates/turborepo-pandacss/scripts/init.sh +92 -0
  228. package/templates/turborepo-pandacss/scripts/setup-dev.ts +640 -0
  229. package/templates/turborepo-pandacss/scripts/template-update.ts +277 -0
  230. package/templates/turborepo-pandacss/scripts/worktree/dev.ts +872 -0
  231. package/templates/turborepo-pandacss/test/globals.d.ts +1 -0
  232. package/templates/turborepo-pandacss/test/setup.ts +22 -0
  233. package/templates/turborepo-pandacss/tsconfig.json +46 -0
  234. package/templates/turborepo-pandacss/turbo.json +57 -0
  235. package/templates/turborepo-pandacss/vitest.config.ts +20 -0
@@ -0,0 +1,175 @@
1
+ "use client";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import {
5
+ ChevronLeftIcon,
6
+ ChevronRightIcon,
7
+ DashboardIcon,
8
+ ExitIcon,
9
+ HamburgerMenuIcon,
10
+ HomeIcon,
11
+ PersonIcon,
12
+ TableIcon,
13
+ } from "@radix-ui/react-icons";
14
+ import { cn } from "{{packageName}}/ui/utils";
15
+ import { signOut } from "next-auth/react";
16
+ import Link from "next/link";
17
+ import { usePathname } from "next/navigation";
18
+ import { useEffect, useState } from "react";
19
+
20
+ interface SidebarProps {
21
+ className?: string;
22
+ isMobileOpen: boolean;
23
+ setIsMobileOpen: (open: boolean) => void;
24
+ }
25
+
26
+ const navigationItems = [
27
+ {
28
+ title: "ホーム",
29
+ href: "/",
30
+ icon: HomeIcon,
31
+ },
32
+ {
33
+ title: "ダッシュボード",
34
+ href: "/dashboard",
35
+ icon: DashboardIcon,
36
+ },
37
+ {
38
+ title: "データ管理",
39
+ href: "/data",
40
+ icon: TableIcon,
41
+ },
42
+ {
43
+ title: "プロフィール",
44
+ href: "/profile",
45
+ icon: PersonIcon,
46
+ },
47
+ ];
48
+
49
+ export function Sidebar({ className, isMobileOpen, setIsMobileOpen }: SidebarProps) {
50
+ const [isDesktopCollapsed, setIsDesktopCollapsed] = useState(() => {
51
+ // ローカルストレージから状態を復元(SSR対応)
52
+ if (typeof window !== "undefined") {
53
+ const saved = localStorage.getItem("sidebar-collapsed");
54
+ return saved ? JSON.parse(saved) : false;
55
+ }
56
+ return false;
57
+ });
58
+ const pathname = usePathname();
59
+
60
+ // デスクトップの折りたたみ状態をローカルストレージに保存
61
+ useEffect(() => {
62
+ localStorage.setItem("sidebar-collapsed", JSON.stringify(isDesktopCollapsed));
63
+ }, [isDesktopCollapsed]);
64
+
65
+ const toggleDesktop = () => setIsDesktopCollapsed(!isDesktopCollapsed);
66
+
67
+ const handleSignOut = async () => {
68
+ await signOut({ callbackUrl: "/signin" });
69
+ };
70
+
71
+ return (
72
+ <>
73
+ {/* Overlay for mobile */}
74
+ {isMobileOpen && (
75
+ // biome-ignore lint/a11y/useKeyWithClickEvents: サイドメニューのオーバーレイ
76
+ <div
77
+ className="fixed inset-0 bg-black/50 z-40 md:hidden"
78
+ onClick={() => setIsMobileOpen(false)}
79
+ aria-hidden="true"
80
+ />
81
+ )}
82
+
83
+ {/* Sidebar */}
84
+ <aside
85
+ className={cn(
86
+ "fixed left-0 top-0 z-50 h-full border-r bg-card text-card-foreground transition-all duration-300 ease-in-out",
87
+ "md:static md:z-auto",
88
+ // Mobile状態
89
+ "md:translate-x-0",
90
+ isMobileOpen ? "translate-x-0 w-64" : "-translate-x-full w-64",
91
+ // Desktop状態
92
+ isDesktopCollapsed ? "md:w-16" : "md:w-64",
93
+ className
94
+ )}
95
+ >
96
+ <div className="flex h-full flex-col">
97
+ {/* Header */}
98
+ <div className="flex items-center justify-between border-b p-4">
99
+ <div className="flex items-center gap-2">
100
+ {!isDesktopCollapsed && <h2 className="text-lg font-semibold">管理システム</h2>}
101
+ {/* Desktop collapse toggle - integrated in sidebar header */}
102
+ <Button
103
+ variant="ghost"
104
+ size="icon"
105
+ className="hidden md:flex"
106
+ onClick={toggleDesktop}
107
+ aria-label={isDesktopCollapsed ? "サイドバーを展開" : "サイドバーを折りたたむ"}
108
+ >
109
+ {isDesktopCollapsed ? (
110
+ <ChevronRightIcon className="h-4 w-4" />
111
+ ) : (
112
+ <ChevronLeftIcon className="h-4 w-4" />
113
+ )}
114
+ </Button>
115
+ </div>
116
+ {/* Mobile close button */}
117
+ <Button
118
+ variant="ghost"
119
+ size="icon"
120
+ className="md:hidden"
121
+ onClick={() => setIsMobileOpen(false)}
122
+ aria-label="メニューを閉じる"
123
+ >
124
+ <ExitIcon className="h-4 w-4" />
125
+ </Button>
126
+ </div>
127
+
128
+ {/* Navigation */}
129
+ <nav className="flex-1 space-y-1 p-4">
130
+ {navigationItems.map((item) => {
131
+ const isActive = pathname === item.href;
132
+ const Icon = item.icon;
133
+
134
+ return (
135
+ <Link
136
+ key={item.href}
137
+ href={item.href}
138
+ className={cn(
139
+ "flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors",
140
+ "hover:bg-accent hover:text-accent-foreground",
141
+ isActive ? "bg-accent text-accent-foreground" : "text-muted-foreground",
142
+ isDesktopCollapsed ? "justify-center" : "gap-3"
143
+ )}
144
+ onClick={() => setIsMobileOpen(false)}
145
+ title={isDesktopCollapsed ? item.title : undefined}
146
+ >
147
+ <Icon className="h-4 w-4 flex-shrink-0" />
148
+ {(!isDesktopCollapsed || isMobileOpen) && (
149
+ <span className="truncate">{item.title}</span>
150
+ )}
151
+ </Link>
152
+ );
153
+ })}
154
+ </nav>
155
+
156
+ {/* Footer with logout */}
157
+ <div className="border-t p-4">
158
+ <Button
159
+ variant="ghost"
160
+ className={cn(
161
+ "w-full transition-all",
162
+ isDesktopCollapsed ? "justify-center px-2" : "justify-start gap-3"
163
+ )}
164
+ onClick={handleSignOut}
165
+ title={isDesktopCollapsed ? "ログアウト" : undefined}
166
+ >
167
+ <ExitIcon className="h-4 w-4 flex-shrink-0" />
168
+ {(!isDesktopCollapsed || isMobileOpen) && <span>ログアウト</span>}
169
+ </Button>
170
+ </div>
171
+ </div>
172
+ </aside>
173
+ </>
174
+ );
175
+ }
@@ -0,0 +1,166 @@
1
+ "use client";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import { HamburgerMenuIcon } from "@radix-ui/react-icons";
5
+ import { css } from "../../../styled-system/css";
6
+ import { hstack, vstack } from "../../../styled-system/patterns";
7
+
8
+ interface HeaderProps {
9
+ user:
10
+ | {
11
+ id?: string;
12
+ name?: string | null;
13
+ email?: string | null;
14
+ image?: string | null;
15
+ }
16
+ | undefined;
17
+ onMobileMenuToggle?: () => void;
18
+ }
19
+
20
+ export function Header({ user, onMobileMenuToggle }: HeaderProps) {
21
+ return (
22
+ <header
23
+ className={css({
24
+ background: "white",
25
+ borderBottom: "1px solid {colors.gray.200}",
26
+ boxShadow: "sm",
27
+ })}
28
+ >
29
+ <div
30
+ className={css({
31
+ maxWidth: "7xl",
32
+ margin: "0 auto",
33
+ padding: {
34
+ base: "1rem 1rem",
35
+ md: "1.25rem 1.5rem",
36
+ lg: "1.5rem 2rem",
37
+ },
38
+ })}
39
+ >
40
+ <div
41
+ className={hstack({
42
+ justifyContent: "space-between",
43
+ alignItems: "center",
44
+ })}
45
+ >
46
+ {/* ロゴ・ブランド */}
47
+ <div className={hstack({ gap: "0.75rem", alignItems: "center" })}>
48
+ {/* Mobile menu button */}
49
+ {onMobileMenuToggle && (
50
+ <Button
51
+ variant="ghost"
52
+ size="icon"
53
+ onClick={onMobileMenuToggle}
54
+ className={css({
55
+ display: { base: "flex", md: "none" },
56
+ padding: "0.5rem",
57
+ marginRight: "0.5rem",
58
+ })}
59
+ aria-label="メニューを開く"
60
+ >
61
+ <HamburgerMenuIcon className={css({ width: "1.25rem", height: "1.25rem" })} />
62
+ </Button>
63
+ )}
64
+ <div
65
+ className={css({
66
+ width: "2.5rem",
67
+ height: "2.5rem",
68
+ background: "linear-gradient(135deg, {colors.blue.600}, {colors.purple.600})",
69
+ borderRadius: "md",
70
+ display: "flex",
71
+ alignItems: "center",
72
+ justifyContent: "center",
73
+ })}
74
+ >
75
+ <span
76
+ className={css({
77
+ fontSize: "lg",
78
+ fontWeight: "bold",
79
+ color: "white",
80
+ })}
81
+ >
82
+ E
83
+ </span>
84
+ </div>
85
+ <h1
86
+ className={css({
87
+ fontSize: "xl",
88
+ fontWeight: "bold",
89
+ color: "{colors.gray.900}",
90
+ })}
91
+ >
92
+ Einja Management
93
+ </h1>
94
+ </div>
95
+
96
+ {/* ユーザー情報 */}
97
+ <div className={hstack({ gap: "1rem", alignItems: "center" })}>
98
+ <div
99
+ className={vstack({
100
+ gap: "0.125rem",
101
+ alignItems: "flex-end",
102
+ display: { base: "none", md: "flex" },
103
+ })}
104
+ >
105
+ {user?.name && (
106
+ <span
107
+ className={css({
108
+ fontSize: "sm",
109
+ fontWeight: "medium",
110
+ color: "{colors.gray.900}",
111
+ })}
112
+ >
113
+ {user.name}
114
+ </span>
115
+ )}
116
+ <span
117
+ className={css({
118
+ fontSize: "xs",
119
+ color: "{colors.gray.500}",
120
+ })}
121
+ >
122
+ {user?.email}
123
+ </span>
124
+ </div>
125
+
126
+ {/* ユーザーアバター */}
127
+ <div
128
+ className={css({
129
+ width: "2.5rem",
130
+ height: "2.5rem",
131
+ background: user?.image ? "transparent" : "{colors.gray.300}",
132
+ borderRadius: "50%",
133
+ display: "flex",
134
+ alignItems: "center",
135
+ justifyContent: "center",
136
+ overflow: "hidden",
137
+ })}
138
+ >
139
+ {user?.image ? (
140
+ <img
141
+ src={user.image}
142
+ alt={user.name || "User"}
143
+ className={css({
144
+ width: "100%",
145
+ height: "100%",
146
+ objectFit: "cover",
147
+ })}
148
+ />
149
+ ) : (
150
+ <span
151
+ className={css({
152
+ fontSize: "sm",
153
+ fontWeight: "medium",
154
+ color: "{colors.gray.600}",
155
+ })}
156
+ >
157
+ {user?.name?.charAt(0) || user?.email?.charAt(0) || "U"}
158
+ </span>
159
+ )}
160
+ </div>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </header>
165
+ );
166
+ }
@@ -0,0 +1,64 @@
1
+ "use client";
2
+
3
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
4
+ import { ChevronDownIcon } from "lucide-react";
5
+ import type * as React from "react";
6
+
7
+ import { cn } from "{{packageName}}/ui/utils";
8
+
9
+ function Accordion({ ...props }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
10
+ return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
11
+ }
12
+
13
+ function AccordionItem({
14
+ className,
15
+ ...props
16
+ }: React.ComponentProps<typeof AccordionPrimitive.Item>) {
17
+ return (
18
+ <AccordionPrimitive.Item
19
+ data-slot="accordion-item"
20
+ className={cn("border-b last:border-b-0", className)}
21
+ {...props}
22
+ />
23
+ );
24
+ }
25
+
26
+ function AccordionTrigger({
27
+ className,
28
+ children,
29
+ ...props
30
+ }: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
31
+ return (
32
+ <AccordionPrimitive.Header className="flex">
33
+ <AccordionPrimitive.Trigger
34
+ data-slot="accordion-trigger"
35
+ className={cn(
36
+ "focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
37
+ className
38
+ )}
39
+ {...props}
40
+ >
41
+ {children}
42
+ <ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
43
+ </AccordionPrimitive.Trigger>
44
+ </AccordionPrimitive.Header>
45
+ );
46
+ }
47
+
48
+ function AccordionContent({
49
+ className,
50
+ children,
51
+ ...props
52
+ }: React.ComponentProps<typeof AccordionPrimitive.Content>) {
53
+ return (
54
+ <AccordionPrimitive.Content
55
+ data-slot="accordion-content"
56
+ className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
57
+ {...props}
58
+ >
59
+ <div className={cn("pt-0 pb-4", className)}>{children}</div>
60
+ </AccordionPrimitive.Content>
61
+ );
62
+ }
63
+
64
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
@@ -0,0 +1,135 @@
1
+ "use client";
2
+
3
+ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
4
+ import type * as React from "react";
5
+
6
+ import { buttonVariants } from "@/components/ui/button";
7
+ import { cn } from "{{packageName}}/ui/utils";
8
+
9
+ function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
10
+ return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
11
+ }
12
+
13
+ function AlertDialogTrigger({
14
+ ...props
15
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
16
+ return <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />;
17
+ }
18
+
19
+ function AlertDialogPortal({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
20
+ return <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />;
21
+ }
22
+
23
+ function AlertDialogOverlay({
24
+ className,
25
+ ...props
26
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
27
+ return (
28
+ <AlertDialogPrimitive.Overlay
29
+ data-slot="alert-dialog-overlay"
30
+ className={cn(
31
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
32
+ className
33
+ )}
34
+ {...props}
35
+ />
36
+ );
37
+ }
38
+
39
+ function AlertDialogContent({
40
+ className,
41
+ ...props
42
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
43
+ return (
44
+ <AlertDialogPortal>
45
+ <AlertDialogOverlay />
46
+ <AlertDialogPrimitive.Content
47
+ data-slot="alert-dialog-content"
48
+ className={cn(
49
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
50
+ className
51
+ )}
52
+ {...props}
53
+ />
54
+ </AlertDialogPortal>
55
+ );
56
+ }
57
+
58
+ function AlertDialogHeader({ className, ...props }: React.ComponentProps<"div">) {
59
+ return (
60
+ <div
61
+ data-slot="alert-dialog-header"
62
+ className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
63
+ {...props}
64
+ />
65
+ );
66
+ }
67
+
68
+ function AlertDialogFooter({ className, ...props }: React.ComponentProps<"div">) {
69
+ return (
70
+ <div
71
+ data-slot="alert-dialog-footer"
72
+ className={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
73
+ {...props}
74
+ />
75
+ );
76
+ }
77
+
78
+ function AlertDialogTitle({
79
+ className,
80
+ ...props
81
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
82
+ return (
83
+ <AlertDialogPrimitive.Title
84
+ data-slot="alert-dialog-title"
85
+ className={cn("text-lg font-semibold", className)}
86
+ {...props}
87
+ />
88
+ );
89
+ }
90
+
91
+ function AlertDialogDescription({
92
+ className,
93
+ ...props
94
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
95
+ return (
96
+ <AlertDialogPrimitive.Description
97
+ data-slot="alert-dialog-description"
98
+ className={cn("text-muted-foreground text-sm", className)}
99
+ {...props}
100
+ />
101
+ );
102
+ }
103
+
104
+ function AlertDialogAction({
105
+ className,
106
+ ...props
107
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
108
+ return <AlertDialogPrimitive.Action className={cn(buttonVariants(), className)} {...props} />;
109
+ }
110
+
111
+ function AlertDialogCancel({
112
+ className,
113
+ ...props
114
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
115
+ return (
116
+ <AlertDialogPrimitive.Cancel
117
+ className={cn(buttonVariants({ variant: "outline" }), className)}
118
+ {...props}
119
+ />
120
+ );
121
+ }
122
+
123
+ export {
124
+ AlertDialog,
125
+ AlertDialogPortal,
126
+ AlertDialogOverlay,
127
+ AlertDialogTrigger,
128
+ AlertDialogContent,
129
+ AlertDialogHeader,
130
+ AlertDialogFooter,
131
+ AlertDialogTitle,
132
+ AlertDialogDescription,
133
+ AlertDialogAction,
134
+ AlertDialogCancel,
135
+ };
@@ -0,0 +1,60 @@
1
+ import { type VariantProps, cva } from "class-variance-authority";
2
+ import type * as React from "react";
3
+
4
+ import { cn } from "{{packageName}}/ui/utils";
5
+
6
+ const alertVariants = cva(
7
+ "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: "bg-card text-card-foreground",
12
+ destructive:
13
+ "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
14
+ },
15
+ },
16
+ defaultVariants: {
17
+ variant: "default",
18
+ },
19
+ }
20
+ );
21
+
22
+ function Alert({
23
+ className,
24
+ variant,
25
+ ...props
26
+ }: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
27
+ return (
28
+ <div
29
+ data-slot="alert"
30
+ role="alert"
31
+ className={cn(alertVariants({ variant }), className)}
32
+ {...props}
33
+ />
34
+ );
35
+ }
36
+
37
+ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
38
+ return (
39
+ <div
40
+ data-slot="alert-title"
41
+ className={cn("col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", className)}
42
+ {...props}
43
+ />
44
+ );
45
+ }
46
+
47
+ function AlertDescription({ className, ...props }: React.ComponentProps<"div">) {
48
+ return (
49
+ <div
50
+ data-slot="alert-description"
51
+ className={cn(
52
+ "text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
53
+ className
54
+ )}
55
+ {...props}
56
+ />
57
+ );
58
+ }
59
+
60
+ export { Alert, AlertTitle, AlertDescription };
@@ -0,0 +1,9 @@
1
+ "use client";
2
+
3
+ import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio";
4
+
5
+ function AspectRatio({ ...props }: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
6
+ return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />;
7
+ }
8
+
9
+ export { AspectRatio };
@@ -0,0 +1,41 @@
1
+ "use client";
2
+
3
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
4
+ import type * as React from "react";
5
+
6
+ import { cn } from "{{packageName}}/ui/utils";
7
+
8
+ function Avatar({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Root>) {
9
+ return (
10
+ <AvatarPrimitive.Root
11
+ data-slot="avatar"
12
+ className={cn("relative flex size-8 shrink-0 overflow-hidden rounded-full", className)}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+
18
+ function AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
19
+ return (
20
+ <AvatarPrimitive.Image
21
+ data-slot="avatar-image"
22
+ className={cn("aspect-square size-full", className)}
23
+ {...props}
24
+ />
25
+ );
26
+ }
27
+
28
+ function AvatarFallback({
29
+ className,
30
+ ...props
31
+ }: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
32
+ return (
33
+ <AvatarPrimitive.Fallback
34
+ data-slot="avatar-fallback"
35
+ className={cn("bg-muted flex size-full items-center justify-center rounded-full", className)}
36
+ {...props}
37
+ />
38
+ );
39
+ }
40
+
41
+ export { Avatar, AvatarImage, AvatarFallback };
@@ -0,0 +1,39 @@
1
+ import { Slot } from "@radix-ui/react-slot";
2
+ import { type VariantProps, cva } from "class-variance-authority";
3
+ import type * as React from "react";
4
+
5
+ import { cn } from "{{packageName}}/ui/utils";
6
+
7
+ const badgeVariants = cva(
8
+ "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
13
+ secondary:
14
+ "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
15
+ destructive:
16
+ "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
17
+ outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ variant: "default",
22
+ },
23
+ }
24
+ );
25
+
26
+ function Badge({
27
+ className,
28
+ variant,
29
+ asChild = false,
30
+ ...props
31
+ }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
32
+ const Comp = asChild ? Slot : "span";
33
+
34
+ return (
35
+ <Comp data-slot="badge" className={cn(badgeVariants({ variant }), className)} {...props} />
36
+ );
37
+ }
38
+
39
+ export { Badge, badgeVariants };