create-next-imagicma 0.0.6 → 0.0.8

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 (78) hide show
  1. package/package.json +1 -1
  2. package/template/opencode.json +7 -0
  3. package/template/package.json +1 -1
  4. package/template/pnpm-lock.yaml +12 -12
  5. package/template-hono/AGENTS.md +55 -7
  6. package/template-hono/README.md +10 -0
  7. package/template-hono/{index.html → client/index.html} +2 -2
  8. package/template-hono/{components → client/src/components}/ui/alert-dialog.tsx +9 -3
  9. package/template-hono/{components → client/src/components}/ui/button.tsx +10 -13
  10. package/template-hono/{components → client/src/components}/ui/card.tsx +3 -3
  11. package/template-hono/{components → client/src/components}/ui/checkbox.tsx +2 -2
  12. package/template-hono/client/src/components/ui/input.tsx +25 -0
  13. package/template-hono/{components → client/src/components}/ui/select.tsx +3 -3
  14. package/template-hono/client/src/components/ui/textarea.tsx +24 -0
  15. package/template-hono/client/src/globals.css +152 -108
  16. package/template-hono/{lib → client/src/lib}/theme/default-theme.ts +1 -1
  17. package/template-hono/opencode.json +7 -0
  18. package/template-hono/package.json +2 -1
  19. package/template-hono/pnpm-lock.yaml +22 -8
  20. package/template-hono/tailwind.config.mjs +1 -4
  21. package/template-hono/tsconfig.json +1 -7
  22. package/template-hono/vite.config.ts +3 -2
  23. package/template-hono/.imagicma/AGENTS.md +0 -7
  24. package/template-hono/.imagicma/port.json +0 -5
  25. package/template-hono/components/ui/input.tsx +0 -25
  26. package/template-hono/components/ui/textarea.tsx +0 -24
  27. /package/template-hono/{public → client/public}/favicon.ico +0 -0
  28. /package/template-hono/{public → client/public}/file.svg +0 -0
  29. /package/template-hono/{public → client/public}/globe.svg +0 -0
  30. /package/template-hono/{public → client/public}/imagicma-picker-bridge.js +0 -0
  31. /package/template-hono/{public → client/public}/next.svg +0 -0
  32. /package/template-hono/{public → client/public}/vercel.svg +0 -0
  33. /package/template-hono/{public → client/public}/window.svg +0 -0
  34. /package/template-hono/{components → client/src/components}/ui/accordion.tsx +0 -0
  35. /package/template-hono/{components → client/src/components}/ui/alert.tsx +0 -0
  36. /package/template-hono/{components → client/src/components}/ui/aspect-ratio.tsx +0 -0
  37. /package/template-hono/{components → client/src/components}/ui/avatar.tsx +0 -0
  38. /package/template-hono/{components → client/src/components}/ui/badge.tsx +0 -0
  39. /package/template-hono/{components → client/src/components}/ui/breadcrumb.tsx +0 -0
  40. /package/template-hono/{components → client/src/components}/ui/calendar.tsx +0 -0
  41. /package/template-hono/{components → client/src/components}/ui/carousel.tsx +0 -0
  42. /package/template-hono/{components → client/src/components}/ui/chart.tsx +0 -0
  43. /package/template-hono/{components → client/src/components}/ui/collapsible.tsx +0 -0
  44. /package/template-hono/{components → client/src/components}/ui/command.tsx +0 -0
  45. /package/template-hono/{components → client/src/components}/ui/context-menu.tsx +0 -0
  46. /package/template-hono/{components → client/src/components}/ui/dialog.tsx +0 -0
  47. /package/template-hono/{components → client/src/components}/ui/drawer.tsx +0 -0
  48. /package/template-hono/{components → client/src/components}/ui/dropdown-menu.tsx +0 -0
  49. /package/template-hono/{components → client/src/components}/ui/form.tsx +0 -0
  50. /package/template-hono/{components → client/src/components}/ui/hover-card.tsx +0 -0
  51. /package/template-hono/{components → client/src/components}/ui/input-otp.tsx +0 -0
  52. /package/template-hono/{components → client/src/components}/ui/label.tsx +0 -0
  53. /package/template-hono/{components → client/src/components}/ui/menubar.tsx +0 -0
  54. /package/template-hono/{components → client/src/components}/ui/navigation-menu.tsx +0 -0
  55. /package/template-hono/{components → client/src/components}/ui/pagination.tsx +0 -0
  56. /package/template-hono/{components → client/src/components}/ui/popover.tsx +0 -0
  57. /package/template-hono/{components → client/src/components}/ui/progress.tsx +0 -0
  58. /package/template-hono/{components → client/src/components}/ui/radio-group.tsx +0 -0
  59. /package/template-hono/{components → client/src/components}/ui/resizable.tsx +0 -0
  60. /package/template-hono/{components → client/src/components}/ui/scroll-area.tsx +0 -0
  61. /package/template-hono/{components → client/src/components}/ui/separator.tsx +0 -0
  62. /package/template-hono/{components → client/src/components}/ui/sheet.tsx +0 -0
  63. /package/template-hono/{components → client/src/components}/ui/sidebar.tsx +0 -0
  64. /package/template-hono/{components → client/src/components}/ui/skeleton.tsx +0 -0
  65. /package/template-hono/{components → client/src/components}/ui/slider.tsx +0 -0
  66. /package/template-hono/{components → client/src/components}/ui/switch.tsx +0 -0
  67. /package/template-hono/{components → client/src/components}/ui/table.tsx +0 -0
  68. /package/template-hono/{components → client/src/components}/ui/tabs.tsx +0 -0
  69. /package/template-hono/{components → client/src/components}/ui/toast.tsx +0 -0
  70. /package/template-hono/{components → client/src/components}/ui/toaster.tsx +0 -0
  71. /package/template-hono/{components → client/src/components}/ui/toggle-group.tsx +0 -0
  72. /package/template-hono/{components → client/src/components}/ui/toggle.tsx +0 -0
  73. /package/template-hono/{components → client/src/components}/ui/tooltip.tsx +0 -0
  74. /package/template-hono/{hooks → client/src/hooks}/use-greeting.ts +0 -0
  75. /package/template-hono/{hooks → client/src/hooks}/use-mobile.ts +0 -0
  76. /package/template-hono/{hooks → client/src/hooks}/use-toast.ts +0 -0
  77. /package/template-hono/{lib → client/src/lib}/queryClient.ts +0 -0
  78. /package/template-hono/{lib → client/src/lib}/utils.ts +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-next-imagicma",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "create-next-imagicma": "./bin/create-next-imagicma.mjs"
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "plugin": [
4
+ "file:///Users/alexliu/Project/oh-my-imagicma/dist/index.js"
5
+ ],
6
+ "default_agent": "ibuild"
7
+ }
@@ -59,7 +59,7 @@
59
59
  "recharts": "^2.15.2",
60
60
  "tailwind-merge": "^2.6.0",
61
61
  "vaul": "^1.1.2",
62
- "zod": "^3.24.2"
62
+ "zod": "^4.1.5"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@tailwindcss/postcss": "^4",
@@ -106,7 +106,7 @@ importers:
106
106
  version: 0.39.3(pg@8.18.0)
107
107
  drizzle-zod:
108
108
  specifier: ^0.7.0
109
- version: 0.7.1(drizzle-orm@0.39.3(pg@8.18.0))(zod@3.25.76)
109
+ version: 0.7.1(drizzle-orm@0.39.3(pg@8.18.0))(zod@4.3.6)
110
110
  embla-carousel-react:
111
111
  specifier: ^8.6.0
112
112
  version: 8.6.0(react@19.2.3)
@@ -153,8 +153,8 @@ importers:
153
153
  specifier: ^1.1.2
154
154
  version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
155
155
  zod:
156
- specifier: ^3.24.2
157
- version: 3.25.76
156
+ specifier: ^4.1.5
157
+ version: 4.3.6
158
158
  devDependencies:
159
159
  '@tailwindcss/postcss':
160
160
  specifier: ^4
@@ -3534,8 +3534,8 @@ packages:
3534
3534
  peerDependencies:
3535
3535
  zod: ^3.25.0 || ^4.0.0
3536
3536
 
3537
- zod@3.25.76:
3538
- resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
3537
+ zod@4.3.6:
3538
+ resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
3539
3539
 
3540
3540
  snapshots:
3541
3541
 
@@ -5339,10 +5339,10 @@ snapshots:
5339
5339
  optionalDependencies:
5340
5340
  pg: 8.18.0
5341
5341
 
5342
- drizzle-zod@0.7.1(drizzle-orm@0.39.3(pg@8.18.0))(zod@3.25.76):
5342
+ drizzle-zod@0.7.1(drizzle-orm@0.39.3(pg@8.18.0))(zod@4.3.6):
5343
5343
  dependencies:
5344
5344
  drizzle-orm: 0.39.3(pg@8.18.0)
5345
- zod: 3.25.76
5345
+ zod: 4.3.6
5346
5346
 
5347
5347
  dunder-proto@1.0.1:
5348
5348
  dependencies:
@@ -5645,8 +5645,8 @@ snapshots:
5645
5645
  '@babel/parser': 7.29.0
5646
5646
  eslint: 9.39.2(jiti@2.6.1)
5647
5647
  hermes-parser: 0.25.1
5648
- zod: 3.25.76
5649
- zod-validation-error: 4.0.2(zod@3.25.76)
5648
+ zod: 4.3.6
5649
+ zod-validation-error: 4.0.2(zod@4.3.6)
5650
5650
  transitivePeerDependencies:
5651
5651
  - supports-color
5652
5652
 
@@ -6930,8 +6930,8 @@ snapshots:
6930
6930
 
6931
6931
  yocto-queue@0.1.0: {}
6932
6932
 
6933
- zod-validation-error@4.0.2(zod@3.25.76):
6933
+ zod-validation-error@4.0.2(zod@4.3.6):
6934
6934
  dependencies:
6935
- zod: 3.25.76
6935
+ zod: 4.3.6
6936
6936
 
6937
- zod@3.25.76: {}
6937
+ zod@4.3.6: {}
@@ -2,23 +2,28 @@
2
2
 
3
3
  默认使用中文沟通与输出(除非用户明确要求其他语言)。
4
4
 
5
+ ## 目标
6
+
7
+ 你需要一次性交付可运行、可预览、可验证、可演示的完整应用,而不是半成品。
8
+
5
9
  ## 技术栈与约束
6
10
 
7
11
  - 框架:Hono(Node runtime)+ Vite(单进程开发)
8
12
  - 前端:React 19 + React Router + Tailwind v4 + shadcn/ui
9
13
  - 请求层:React Query + fetch
10
14
  - 契约:Zod(`shared/routes.ts`)
11
- - 数据库:Postgres + Drizzle
15
+ - 数据库:优先 Postgres + Drizzle;若 `DATABASE_URL` 缺失,默认走 SQLite(零配置)并保持 API 契约不变
12
16
 
13
17
  ## 目录约定
14
18
 
19
+ - `client/index.html`:Vite 前端入口 HTML
20
+ - `client/public/`:前端静态资源
15
21
  - `client/src/`:前端应用入口、页面、Provider、错误边界
22
+ - `client/src/components/ui/`:shadcn/ui 组件
23
+ - `client/src/hooks/`:客户端 hooks
24
+ - `client/src/lib/`:通用工具
16
25
  - `server/`:Hono 入口、路由、存储、DB
17
- - `components/ui/`:shadcn/ui 组件
18
- - `hooks/`:客户端 hooks
19
- - `lib/`:通用工具
20
26
  - `shared/`:前后端共享 schema/契约
21
- - `public/`:静态资源(由 Vite/Hono 提供)
22
27
 
23
28
  ## 常用命令
24
29
 
@@ -29,11 +34,54 @@
29
34
  - `pnpm lint`:ESLint
30
35
  - `pnpm db:push`:同步数据库结构
31
36
 
32
- ## 开发规则
37
+ ## 执行硬规则
38
+
39
+ - 不阻塞就不要问用户,直接推进到完成。
40
+ - 不要要求用户发送“继续执行/不要停在总结”之类控制语句,把持续推进作为默认行为。
41
+ - 进度反馈用自然里程碑播报,不使用突兀命令式话术。
42
+ - 仅在真实阻塞时才提问,并附已尝试步骤与日志证据。
43
+ - 未达到完成标准前,不得用“文档总结/状态总结”代替执行。
44
+ - 不得只做前端占位,必须打通真实 API 与数据读写链路。
45
+ - 每次代码改动后必须重启服务并验证页面/接口。
46
+ - 关键改动后必须跑端到端验证(如 `run_test`)并检查日志。
47
+ - 禁止递归调用测试代理或无限循环调用同一工具。
48
+ - 如果 `run_test` 结果不是 `[run_test] ok`,必须视为未通过,继续修复。
49
+ - `run_test` 卡住或无进展时要快速失败并给出证据,禁止长时间空转重试。
50
+ - 不允许“口头完成”。完成声明必须有工具证据支撑。
51
+ - SQLite 路径必须保持单一 schema 真相源,禁止手写临时 SQL 与 ORM schema 并行漂移。
52
+
53
+ ## 状态文件写入规则
54
+
55
+ - 若维护 `docs/project_state.json`,每次写入前先读取最新版本。
56
+ - 若写入报冲突(文件已变更),必须重新读取后重试,不得忽略。
57
+ - `quality_gates.typecheck=true` 仅在构建命令真实通过后设置。
58
+
59
+ ## UI 质量门禁(必须全部满足)
60
+
61
+ - 首页不得空白,不得仅显示默认模板文案。
62
+ - 视觉风格必须明确:字体、颜色、间距、动效要统一。
63
+ - 禁止“紫色渐变 + 白底默认感”模板化输出。
64
+ - 必须定义可复用设计 token(颜色、圆角、阴影、间距等级)。
65
+ - 至少覆盖桌面与移动端关键断点,不允许内容溢出。
66
+ - 交互状态完整:hover/focus/disabled/loading/error/success。
67
+ - 在 `<Button>` 上使用自定义背景色类(如 `bg-*`)时,必须同时显式声明文本色类(如 `text-*`);禁止只改背景不改文字色。
68
+ - Todo 类页面优先采用单主轴布局(标题区 + 输入区 + 列表区),避免信息噪音过载。
69
+ - 优先复用 `Input/Button/Card/Checkbox/Select` 的默认视觉语言,必要时只做局部增强,不要重写整套样式。
70
+ - 列表增删改状态建议加入轻量动效(如 `framer-motion` 的入场/退出),并提供失败反馈(toast 或 inline alert)。
71
+
72
+ ## 数据与安全
33
73
 
34
74
  - 服务端数据库逻辑放在 `server/`,不要泄漏到客户端。
35
75
  - API 响应必须经过 `shared/routes.ts` 的 Zod schema 校验。
36
76
  - 不提交 `.env.local`、数据库密钥。
37
- - 优先复用 `components/ui` 与已有 hooks,避免重复造轮子。
77
+ - 优先复用 `client/src/components/ui` `client/src/hooks`,避免重复造轮子。
78
+
79
+ ## 完成标准
38
80
 
81
+ 只有以下全部满足才允许结束:
39
82
 
83
+ - `pnpm build` 通过(无 pnpm 时 `npm run build` 通过)
84
+ - 页面可在本地端口访问并完成核心流程
85
+ - `run_test` 返回 `[run_test] ok`
86
+ - 关键日志无阻塞级错误
87
+ - UI 达到可演示级(非“功能可用但观感粗糙”)
@@ -9,6 +9,16 @@
9
9
  - 数据层:Drizzle ORM + PostgreSQL (`pg`)
10
10
  - 校验契约:Zod(`shared/routes.ts`)
11
11
 
12
+ ## 目录结构(重点)
13
+
14
+ - `client/index.html`:前端入口 HTML
15
+ - `client/public/`:前端静态资源
16
+ - `client/src/components/ui/`:shadcn/ui 组件
17
+ - `client/src/hooks/`:前端 hooks
18
+ - `client/src/lib/`:前端通用工具
19
+ - `server/`:Hono 后端入口与路由
20
+ - `shared/`:前后端共享契约与 schema
21
+
12
22
  ## 开发
13
23
 
14
24
  ```bash
@@ -1,5 +1,5 @@
1
1
  <!doctype html>
2
- <html lang="zh-CN" data-theme-style="quadratic">
2
+ <html lang="zh-CN" data-theme-style="nomad">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
@@ -8,6 +8,6 @@
8
8
  </head>
9
9
  <body class="antialiased">
10
10
  <div id="root"></div>
11
- <script type="module" src="/client/src/main.tsx"></script>
11
+ <script type="module" src="/src/main.tsx"></script>
12
12
  </body>
13
13
  </html>
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as React from "react"
4
4
  import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
5
+ import type { VariantProps } from "class-variance-authority"
5
6
 
6
7
  import { cn } from "@/lib/utils"
7
8
  import { buttonVariants } from "@/components/ui/button"
@@ -98,13 +99,18 @@ const AlertDialogDescription = React.forwardRef<
98
99
  AlertDialogDescription.displayName =
99
100
  AlertDialogPrimitive.Description.displayName
100
101
 
102
+ type AlertDialogActionProps = React.ComponentPropsWithoutRef<
103
+ typeof AlertDialogPrimitive.Action
104
+ > &
105
+ VariantProps<typeof buttonVariants>
106
+
101
107
  const AlertDialogAction = React.forwardRef<
102
108
  React.ElementRef<typeof AlertDialogPrimitive.Action>,
103
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
104
- >(({ className, ...props }, ref) => (
109
+ AlertDialogActionProps
110
+ >(({ className, variant, size, ...props }, ref) => (
105
111
  <AlertDialogPrimitive.Action
106
112
  ref={ref}
107
- className={cn(buttonVariants(), className)}
113
+ className={cn(buttonVariants({ variant, size }), className)}
108
114
  {...props}
109
115
  />
110
116
  ))
@@ -7,31 +7,28 @@ import { cva, type VariantProps } from "class-variance-authority"
7
7
  import { cn } from "@/lib/utils"
8
8
 
9
9
  const buttonVariants = cva(
10
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0" +
11
- " hover-elevate active-elevate-2",
10
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xl text-sm font-semibold tracking-[0.01em] transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
12
11
  {
13
12
  variants: {
14
13
  variant: {
15
14
  default:
16
- "bg-primary text-primary-foreground border border-primary-border",
15
+ "bg-primary text-primary-foreground border border-primary/45 shadow-[0_10px_24px_hsl(var(--primary)/0.38)] hover:-translate-y-0.5 hover:shadow-[0_14px_30px_hsl(var(--primary)/0.46)] active:translate-y-0",
17
16
  destructive:
18
- "bg-destructive text-destructive-foreground border border-destructive-border",
17
+ "bg-destructive text-destructive-foreground border border-destructive/45 shadow-[0_10px_22px_hsl(var(--destructive)/0.3)] hover:brightness-105",
19
18
  outline:
20
- // Shows the background color of whatever card / sidebar / accent background it is inside of.
21
- // Inherits the current text color.
22
- " border [border-color:var(--button-outline)] shadow-xs active:shadow-none ",
23
- secondary: "border bg-secondary text-secondary-foreground border border-secondary-border ",
19
+ "border border-input/80 bg-white/75 text-foreground shadow-[0_4px_12px_rgba(15,23,42,0.08)] hover:bg-white hover:border-ring/35",
20
+ secondary: "border border-secondary-border bg-secondary/90 text-secondary-foreground shadow-sm hover:bg-secondary",
24
21
  // Add a transparent border so that when someone toggles a border on later, it doesn't shift layout/size.
25
- ghost: "border border-transparent",
22
+ ghost: "border border-transparent text-foreground/80 hover:bg-accent/75 hover:text-foreground",
26
23
  },
27
24
  // Heights are set as "min" heights, because sometimes Ai will place large amount of content
28
25
  // inside buttons. With a min-height they will look appropriate with small amounts of content,
29
26
  // but will expand to fit large amounts of content.
30
27
  size: {
31
- default: "min-h-9 px-4 py-2",
32
- sm: "min-h-8 rounded-md px-3 text-xs",
33
- lg: "min-h-10 rounded-md px-8",
34
- icon: "h-9 w-9",
28
+ default: "min-h-10 px-4 py-2",
29
+ sm: "min-h-8 rounded-lg px-3 text-xs",
30
+ lg: "min-h-11 rounded-xl px-8",
31
+ icon: "h-10 w-10 rounded-xl",
35
32
  },
36
33
  },
37
34
  defaultVariants: {
@@ -11,7 +11,7 @@ const Card = React.forwardRef<
11
11
  <div
12
12
  ref={ref}
13
13
  className={cn(
14
- "shadcn-card rounded-xl border bg-card border-card-border text-card-foreground shadow-sm",
14
+ "shadcn-card rounded-2xl border border-white/70 bg-card/84 text-card-foreground shadow-[0_18px_42px_rgba(15,23,42,0.1)] backdrop-blur",
15
15
  className
16
16
  )}
17
17
  {...props}
@@ -25,7 +25,7 @@ const CardHeader = React.forwardRef<
25
25
  >(({ className, ...props }, ref) => (
26
26
  <div
27
27
  ref={ref}
28
- className={cn("flex flex-col space-y-1.5 p-6", className)}
28
+ className={cn("flex flex-col space-y-1.5 p-5 sm:p-6", className)}
29
29
  {...props}
30
30
  />
31
31
  ));
@@ -38,7 +38,7 @@ const CardTitle = React.forwardRef<
38
38
  <div
39
39
  ref={ref}
40
40
  className={cn(
41
- "text-2xl font-semibold leading-none tracking-tight",
41
+ "text-xl font-semibold leading-tight tracking-tight sm:text-2xl",
42
42
  className
43
43
  )}
44
44
  {...props}
@@ -13,7 +13,7 @@ const Checkbox = React.forwardRef<
13
13
  <CheckboxPrimitive.Root
14
14
  ref={ref}
15
15
  className={cn(
16
- "peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
16
+ "peer h-5 w-5 shrink-0 rounded-full border-2 border-primary/45 bg-white shadow-[0_1px_3px_rgba(15,23,42,0.18)] ring-offset-background transition-[background-color,border-color,box-shadow] duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/35 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:shadow-[0_8px_16px_hsl(var(--primary)/0.35)]",
17
17
  className
18
18
  )}
19
19
  {...props}
@@ -21,7 +21,7 @@ const Checkbox = React.forwardRef<
21
21
  <CheckboxPrimitive.Indicator
22
22
  className={cn("flex items-center justify-center text-current")}
23
23
  >
24
- <Check className="h-4 w-4" />
24
+ <Check className="h-3.5 w-3.5" />
25
25
  </CheckboxPrimitive.Indicator>
26
26
  </CheckboxPrimitive.Root>
27
27
  ))
@@ -0,0 +1,25 @@
1
+ "use client";
2
+
3
+ import * as React from "react"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
8
+ ({ className, type, ...props }, ref) => {
9
+ // h-9 to match icon buttons and default buttons.
10
+ return (
11
+ <input
12
+ type={type}
13
+ className={cn(
14
+ "flex h-11 w-full rounded-2xl border border-input/85 bg-white/82 px-4 py-2 text-[15px] text-foreground shadow-[inset_0_1px_0_rgba(255,255,255,0.86),0_1px_2px_rgba(15,23,42,0.06)] ring-offset-background transition-[border-color,box-shadow,background-color] duration-200 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground/70 focus-visible:outline-none focus-visible:border-primary/55 focus-visible:bg-white focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
15
+ className
16
+ )}
17
+ ref={ref}
18
+ {...props}
19
+ />
20
+ )
21
+ }
22
+ )
23
+ Input.displayName = "Input"
24
+
25
+ export { Input }
@@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
19
19
  <SelectPrimitive.Trigger
20
20
  ref={ref}
21
21
  className={cn(
22
- "flex h-9 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
22
+ "flex h-11 w-full items-center justify-between rounded-2xl border border-input/85 bg-white/82 px-4 py-2 text-sm text-foreground shadow-[inset_0_1px_0_rgba(255,255,255,0.86),0_1px_2px_rgba(15,23,42,0.06)] ring-offset-background transition-[border-color,box-shadow,background-color] duration-200 data-[placeholder]:text-muted-foreground/70 focus:outline-none focus:border-primary/55 focus:bg-white focus:ring-2 focus:ring-ring/30 focus:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
23
23
  className
24
24
  )}
25
25
  {...props}
@@ -75,7 +75,7 @@ const SelectContent = React.forwardRef<
75
75
  <SelectPrimitive.Content
76
76
  ref={ref}
77
77
  className={cn(
78
- "relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
78
+ "relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-xl border border-white/70 bg-popover/95 text-popover-foreground shadow-[0_16px_36px_rgba(15,23,42,0.18)] backdrop-blur 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
79
79
  position === "popper" &&
80
80
  "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
81
81
  className
@@ -118,7 +118,7 @@ const SelectItem = React.forwardRef<
118
118
  <SelectPrimitive.Item
119
119
  ref={ref}
120
120
  className={cn(
121
- "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
121
+ "relative flex w-full cursor-default select-none items-center rounded-lg py-2 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent/85 focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
122
122
  className
123
123
  )}
124
124
  {...props}
@@ -0,0 +1,24 @@
1
+ "use client";
2
+
3
+ import * as React from "react"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const Textarea = React.forwardRef<
8
+ HTMLTextAreaElement,
9
+ React.ComponentProps<"textarea">
10
+ >(({ className, ...props }, ref) => {
11
+ return (
12
+ <textarea
13
+ className={cn(
14
+ "flex min-h-[96px] w-full rounded-2xl border border-input/85 bg-white/82 px-4 py-3 text-[15px] shadow-[inset_0_1px_0_rgba(255,255,255,0.86),0_1px_2px_rgba(15,23,42,0.06)] ring-offset-background transition-[border-color,box-shadow,background-color] duration-200 placeholder:text-muted-foreground/70 focus-visible:outline-none focus-visible:border-primary/55 focus-visible:bg-white focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
15
+ className
16
+ )}
17
+ ref={ref}
18
+ {...props}
19
+ />
20
+ )
21
+ })
22
+ Textarea.displayName = "Textarea"
23
+
24
+ export { Textarea }
@@ -1,14 +1,16 @@
1
+ @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700;800&display=swap");
1
2
  @import "tailwindcss";
2
3
  @config "../../tailwind.config.mjs";
3
4
 
4
5
  :root {
5
6
  /* Fonts */
6
- --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
7
- "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
8
- "Helvetica Neue", Arial, "Noto Sans", "Apple Color Emoji", "Segoe UI Emoji",
9
- "Segoe UI Symbol", sans-serif;
10
- --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
11
- --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
7
+ --font-sans: "Poppins", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
8
+ "Noto Sans SC", "Helvetica Neue", sans-serif;
9
+ --font-display: "Poppins", "PingFang SC", "Hiragino Sans GB",
10
+ "Microsoft YaHei", sans-serif;
11
+ --font-serif: "Poppins", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
12
+ "Noto Sans SC", "Helvetica Neue", sans-serif;
13
+ --font-mono: Menlo, ui-monospace, SFMono-Regular, Monaco, Consolas,
12
14
  "Liberation Mono", "Courier New", monospace;
13
15
 
14
16
  /* Core theme tokens (HSL triples) */
@@ -40,7 +42,19 @@
40
42
  --input: 240 5.9% 90%;
41
43
  --ring: 240 5.9% 10%;
42
44
 
43
- --radius: 0.5rem;
45
+ --radius: 0.8rem;
46
+
47
+ /* Visual system tokens for showcase pages */
48
+ --surface-1: 224 40% 98%;
49
+ --surface-2: 220 35% 95%;
50
+ --brand-accent: 201 92% 56%;
51
+ --brand-success: 156 72% 40%;
52
+ --elevation-soft: 0 14px 34px rgba(15, 23, 42, 0.12);
53
+ --elevation-strong: 0 22px 56px rgba(15, 23, 42, 0.18);
54
+ --space-xs: 0.625rem;
55
+ --space-sm: 0.875rem;
56
+ --space-md: 1.125rem;
57
+ --space-lg: 1.625rem;
44
58
 
45
59
  /* Extra tokens used by the migrated shadcn components */
46
60
  --card-border: var(--border);
@@ -115,119 +129,119 @@
115
129
 
116
130
  /* Theme style presets (used by html[data-theme-style="<preset>"]) */
117
131
  :root[data-theme-style="quadratic"] {
118
- --background: 240 8.3% 95.3%;
119
- --foreground: 225 14.3% 5.5%;
132
+ --background: 246 33% 96%;
133
+ --foreground: 233 24% 17%;
120
134
 
121
135
  --card: 0 0% 100%;
122
- --card-foreground: 225 14.3% 5.5%;
136
+ --card-foreground: 233 24% 17%;
123
137
  --popover: 0 0% 100%;
124
- --popover-foreground: 225 14.3% 5.5%;
125
-
126
- --primary: 240 8.6% 93.1%;
127
- --primary-foreground: 225 14.3% 5.5%;
128
- --secondary: 240 7% 86.1%;
129
- --secondary-foreground: 225 14.3% 5.5%;
130
- --muted: 240 8.6% 93.1%;
131
- --muted-foreground: 225 7% 35%;
132
- --accent: 240 7% 86.1%;
133
- --accent-foreground: 225 14.3% 5.5%;
134
-
135
- --border: 240 7% 82%;
136
- --input: 240 7% 82%;
137
- --ring: 225 14.3% 5.5%;
138
-
139
- --chart-1: 225 14.3% 35%;
140
- --chart-2: 240 8% 55%;
141
- --chart-3: 220 40% 55%;
142
- --chart-4: 270 20% 62%;
143
- --chart-5: 190 30% 52%;
138
+ --popover-foreground: 233 24% 17%;
139
+
140
+ --primary: 258 84% 63%;
141
+ --primary-foreground: 0 0% 100%;
142
+ --secondary: 250 44% 92%;
143
+ --secondary-foreground: 233 24% 20%;
144
+ --muted: 246 36% 93%;
145
+ --muted-foreground: 230 12% 42%;
146
+ --accent: 257 62% 88%;
147
+ --accent-foreground: 234 24% 24%;
148
+
149
+ --border: 246 24% 86%;
150
+ --input: 246 24% 84%;
151
+ --ring: 258 84% 63%;
152
+
153
+ --chart-1: 258 78% 56%;
154
+ --chart-2: 201 84% 56%;
155
+ --chart-3: 172 65% 45%;
156
+ --chart-4: 338 74% 58%;
157
+ --chart-5: 39 84% 58%;
144
158
  }
145
159
 
146
160
  .dark[data-theme-style="quadratic"] {
147
- --background: 225 14.3% 5.5%;
148
- --foreground: 240 8.3% 95.3%;
149
-
150
- --card: 225 12% 9%;
151
- --card-foreground: 240 8.3% 95.3%;
152
- --popover: 225 12% 9%;
153
- --popover-foreground: 240 8.3% 95.3%;
154
-
155
- --primary: 240 8.6% 93.1%;
156
- --primary-foreground: 225 14.3% 5.5%;
157
- --secondary: 225 8% 15%;
158
- --secondary-foreground: 240 8.3% 95.3%;
159
- --muted: 225 8% 12%;
160
- --muted-foreground: 240 7% 70%;
161
- --accent: 225 8% 12%;
162
- --accent-foreground: 240 8.3% 95.3%;
163
-
164
- --border: 225 8% 22%;
165
- --input: 225 8% 22%;
166
- --ring: 240 8.6% 93.1%;
167
-
168
- --chart-1: 240 8.6% 70%;
169
- --chart-2: 220 30% 65%;
170
- --chart-3: 190 30% 60%;
171
- --chart-4: 270 20% 65%;
172
- --chart-5: 45 20% 62%;
161
+ --background: 233 22% 11%;
162
+ --foreground: 246 33% 96%;
163
+
164
+ --card: 232 20% 14%;
165
+ --card-foreground: 246 33% 96%;
166
+ --popover: 232 20% 14%;
167
+ --popover-foreground: 246 33% 96%;
168
+
169
+ --primary: 258 90% 70%;
170
+ --primary-foreground: 233 22% 11%;
171
+ --secondary: 235 16% 20%;
172
+ --secondary-foreground: 246 30% 94%;
173
+ --muted: 234 14% 18%;
174
+ --muted-foreground: 240 15% 76%;
175
+ --accent: 235 16% 20%;
176
+ --accent-foreground: 246 30% 94%;
177
+
178
+ --border: 234 14% 26%;
179
+ --input: 234 14% 26%;
180
+ --ring: 258 90% 70%;
181
+
182
+ --chart-1: 258 90% 70%;
183
+ --chart-2: 201 78% 68%;
184
+ --chart-3: 172 58% 62%;
185
+ --chart-4: 338 76% 72%;
186
+ --chart-5: 39 78% 70%;
173
187
  }
174
188
 
175
189
  :root[data-theme-style="nomad"] {
176
- --background: 240 9.1% 95.7%;
177
- --foreground: 220 12.5% 9.4%;
178
-
179
- --card: 240 12% 98%;
180
- --card-foreground: 220 12.5% 9.4%;
181
- --popover: 240 12% 98%;
182
- --popover-foreground: 220 12.5% 9.4%;
183
-
184
- --primary: 339 89.8% 53.9%;
185
- --primary-foreground: 220 12.5% 9.4%;
186
- --secondary: 231 10.4% 86.9%;
187
- --secondary-foreground: 220 12.5% 9.4%;
188
- --muted: 240 9% 92%;
189
- --muted-foreground: 220 8% 35%;
190
- --accent: 231 10.4% 86.9%;
191
- --accent-foreground: 220 12.5% 9.4%;
192
-
193
- --border: 231 10% 82%;
194
- --input: 231 10% 82%;
195
- --ring: 339 89.8% 53.9%;
196
-
197
- --chart-1: 339 89.8% 53.9%;
198
- --chart-2: 220 28% 40%;
199
- --chart-3: 40 72% 60%;
200
- --chart-4: 173 25% 45%;
201
- --chart-5: 280 45% 60%;
190
+ --background: 0 0% 94.1%;
191
+ --foreground: 0 0% 10.2%;
192
+
193
+ --card: 0 0% 98.8%;
194
+ --card-foreground: 0 0% 0%;
195
+ --popover: 45 25% 96.9%;
196
+ --popover-foreground: 0 0% 10.2%;
197
+
198
+ --primary: 341.9 85.1% 52.5%;
199
+ --primary-foreground: 0 0% 100%;
200
+ --secondary: 0 0% 76.9%;
201
+ --secondary-foreground: 0 0% 10.2%;
202
+ --muted: 0 0% 89%;
203
+ --muted-foreground: 0 0% 12.9%;
204
+ --accent: 0 0% 100%;
205
+ --accent-foreground: 0 0% 10.2%;
206
+
207
+ --border: 0 0% 91%;
208
+ --input: 0 0% 71%;
209
+ --ring: 0 0% 42%;
210
+
211
+ --chart-1: 203.9 88.3% 53.1%;
212
+ --chart-2: 159.8 100% 36.1%;
213
+ --chart-3: 42 92.8% 56.3%;
214
+ --chart-4: 147.1 78.5% 42%;
215
+ --chart-5: 341.5 75.2% 51%;
202
216
  }
203
217
 
204
218
  .dark[data-theme-style="nomad"] {
205
- --background: 220 12.5% 9.4%;
206
- --foreground: 240 9.1% 95.7%;
207
-
208
- --card: 220 12% 12%;
209
- --card-foreground: 240 9.1% 95.7%;
210
- --popover: 220 12% 12%;
211
- --popover-foreground: 240 9.1% 95.7%;
212
-
213
- --primary: 339 90% 62%;
214
- --primary-foreground: 220 12.5% 9.4%;
215
- --secondary: 220 10% 17%;
216
- --secondary-foreground: 240 9.1% 95.7%;
217
- --muted: 220 9% 14%;
218
- --muted-foreground: 240 7% 70%;
219
- --accent: 220 9% 14%;
220
- --accent-foreground: 240 9.1% 95.7%;
221
-
222
- --border: 220 8% 22%;
223
- --input: 220 8% 22%;
224
- --ring: 339 90% 62%;
225
-
226
- --chart-1: 339 90% 66%;
227
- --chart-2: 40 72% 65%;
228
- --chart-3: 173 30% 58%;
229
- --chart-4: 280 50% 72%;
230
- --chart-5: 220 18% 72%;
219
+ --background: 0 0% 10%;
220
+ --foreground: 0 0% 96%;
221
+
222
+ --card: 0 0% 13%;
223
+ --card-foreground: 0 0% 98%;
224
+ --popover: 0 0% 8%;
225
+ --popover-foreground: 0 0% 96%;
226
+
227
+ --primary: 341.9 85.1% 60%;
228
+ --primary-foreground: 0 0% 100%;
229
+ --secondary: 0 0% 26%;
230
+ --secondary-foreground: 0 0% 96%;
231
+ --muted: 0 0% 18%;
232
+ --muted-foreground: 0 0% 72%;
233
+ --accent: 0 0% 22%;
234
+ --accent-foreground: 0 0% 96%;
235
+
236
+ --border: 0 0% 24%;
237
+ --input: 0 0% 34%;
238
+ --ring: 0 0% 62%;
239
+
240
+ --chart-1: 203.9 88.3% 62%;
241
+ --chart-2: 159.8 100% 44%;
242
+ --chart-3: 42 92.8% 64%;
243
+ --chart-4: 147.1 78.5% 50%;
244
+ --chart-5: 341.5 75.2% 59%;
231
245
  }
232
246
 
233
247
  :root[data-theme-style="honey"] {
@@ -412,10 +426,40 @@
412
426
  body {
413
427
  @apply bg-background text-foreground antialiased;
414
428
  font-family: var(--font-sans);
429
+ line-height: 1.5;
430
+ text-rendering: optimizeLegibility;
431
+ -webkit-font-smoothing: antialiased;
432
+ -moz-osx-font-smoothing: grayscale;
433
+ }
434
+
435
+ h1,
436
+ h2,
437
+ h3,
438
+ h4 {
439
+ font-family: var(--font-display);
440
+ letter-spacing: -0.02em;
441
+ }
442
+
443
+ ::selection {
444
+ background: hsl(var(--primary) / 0.22);
415
445
  }
416
446
  }
417
447
 
418
448
  @layer utilities {
449
+ @keyframes showcase-rise-in {
450
+ 0% {
451
+ opacity: 0;
452
+ transform: translateY(12px) scale(0.992);
453
+ }
454
+ 100% {
455
+ opacity: 1;
456
+ transform: translateY(0) scale(1);
457
+ }
458
+ }
459
+
460
+ .showcase-rise {
461
+ animation: showcase-rise-in 560ms cubic-bezier(0.2, 0.72, 0.24, 1) both;
462
+ }
419
463
  .hover-elevate {
420
464
  transition: transform 150ms ease, box-shadow 150ms ease;
421
465
  }
@@ -8,4 +8,4 @@ export const THEME_STYLES = [
8
8
 
9
9
  export type ThemeStyle = (typeof THEME_STYLES)[number];
10
10
 
11
- export const DEFAULT_THEME_STYLE: ThemeStyle = "quadratic";
11
+ export const DEFAULT_THEME_STYLE: ThemeStyle = "nomad";
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "plugin": [
4
+ "file:///Users/alexliu/Project/oh-my-imagicma/dist/index.js"
5
+ ],
6
+ "default_agent": "ibuild-omega"
7
+ }
@@ -14,6 +14,7 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@hono/node-server": "^1.19.9",
17
+ "@hono/zod-validator": "^0.7.6",
17
18
  "@radix-ui/react-accordion": "^1.2.4",
18
19
  "@radix-ui/react-alert-dialog": "^1.1.7",
19
20
  "@radix-ui/react-aspect-ratio": "^1.1.3",
@@ -63,7 +64,7 @@
63
64
  "recharts": "^2.15.2",
64
65
  "tailwind-merge": "^2.6.0",
65
66
  "vaul": "^1.1.2",
66
- "zod": "^3.24.2"
67
+ "zod": "^4.1.5"
67
68
  },
68
69
  "devDependencies": {
69
70
  "@hono/vite-dev-server": "^0.25.0",
@@ -11,6 +11,9 @@ importers:
11
11
  '@hono/node-server':
12
12
  specifier: ^1.19.9
13
13
  version: 1.19.9(hono@4.11.9)
14
+ '@hono/zod-validator':
15
+ specifier: ^0.7.6
16
+ version: 0.7.6(hono@4.11.9)(zod@4.3.6)
14
17
  '@radix-ui/react-accordion':
15
18
  specifier: ^1.2.4
16
19
  version: 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -109,7 +112,7 @@ importers:
109
112
  version: 0.39.3(pg@8.18.0)
110
113
  drizzle-zod:
111
114
  specifier: ^0.7.0
112
- version: 0.7.1(drizzle-orm@0.39.3(pg@8.18.0))(zod@3.25.76)
115
+ version: 0.7.1(drizzle-orm@0.39.3(pg@8.18.0))(zod@4.3.6)
113
116
  embla-carousel-react:
114
117
  specifier: ^8.6.0
115
118
  version: 8.6.0(react@19.2.3)
@@ -159,8 +162,8 @@ importers:
159
162
  specifier: ^1.1.2
160
163
  version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
161
164
  zod:
162
- specifier: ^3.24.2
163
- version: 3.25.76
165
+ specifier: ^4.1.5
166
+ version: 4.3.6
164
167
  devDependencies:
165
168
  '@hono/vite-dev-server':
166
169
  specifier: ^0.25.0
@@ -822,6 +825,12 @@ packages:
822
825
  wrangler:
823
826
  optional: true
824
827
 
828
+ '@hono/zod-validator@0.7.6':
829
+ resolution: {integrity: sha512-Io1B6d011Gj1KknV4rXYz4le5+5EubcWEU/speUjuw9XMMIaP3n78yXLhjd2A3PXaXaUwEAluOiAyLqhBEJgsw==}
830
+ peerDependencies:
831
+ hono: '>=3.9.0'
832
+ zod: ^3.25.0 || ^4.0.0
833
+
825
834
  '@humanfs/core@0.19.1':
826
835
  resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
827
836
  engines: {node: '>=18.18.0'}
@@ -2850,8 +2859,8 @@ packages:
2850
2859
  resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
2851
2860
  engines: {node: '>=10'}
2852
2861
 
2853
- zod@3.25.76:
2854
- resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
2862
+ zod@4.3.6:
2863
+ resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
2855
2864
 
2856
2865
  snapshots:
2857
2866
 
@@ -3280,6 +3289,11 @@ snapshots:
3280
3289
  hono: 4.11.9
3281
3290
  minimatch: 9.0.5
3282
3291
 
3292
+ '@hono/zod-validator@0.7.6(hono@4.11.9)(zod@4.3.6)':
3293
+ dependencies:
3294
+ hono: 4.11.9
3295
+ zod: 4.3.6
3296
+
3283
3297
  '@humanfs/core@0.19.1': {}
3284
3298
 
3285
3299
  '@humanfs/node@0.16.7':
@@ -4396,10 +4410,10 @@ snapshots:
4396
4410
  optionalDependencies:
4397
4411
  pg: 8.18.0
4398
4412
 
4399
- drizzle-zod@0.7.1(drizzle-orm@0.39.3(pg@8.18.0))(zod@3.25.76):
4413
+ drizzle-zod@0.7.1(drizzle-orm@0.39.3(pg@8.18.0))(zod@4.3.6):
4400
4414
  dependencies:
4401
4415
  drizzle-orm: 0.39.3(pg@8.18.0)
4402
- zod: 3.25.76
4416
+ zod: 4.3.6
4403
4417
 
4404
4418
  electron-to-chromium@1.5.286: {}
4405
4419
 
@@ -5159,4 +5173,4 @@ snapshots:
5159
5173
 
5160
5174
  yocto-queue@0.1.0: {}
5161
5175
 
5162
- zod@3.25.76: {}
5176
+ zod@4.3.6: {}
@@ -4,11 +4,8 @@ import animate from "tailwindcss-animate";
4
4
  const config = {
5
5
  darkMode: ["class"],
6
6
  content: [
7
- "./index.html",
7
+ "./client/index.html",
8
8
  "./client/src/**/*.{ts,tsx}",
9
- "./components/**/*.{ts,tsx}",
10
- "./hooks/**/*.{ts,tsx}",
11
- "./lib/**/*.{ts,tsx}",
12
9
  "./shared/**/*.{ts,tsx}",
13
10
  ],
14
11
  theme: {
@@ -15,19 +15,13 @@
15
15
  "incremental": true,
16
16
  "types": ["node", "vite/client"],
17
17
  "paths": {
18
- "@/*": ["./*"],
18
+ "@/*": ["./client/src/*"],
19
19
  "@shared/*": ["./shared/*"]
20
20
  }
21
21
  },
22
22
  "include": [
23
23
  "client/src/**/*.ts",
24
24
  "client/src/**/*.tsx",
25
- "components/**/*.ts",
26
- "components/**/*.tsx",
27
- "hooks/**/*.ts",
28
- "hooks/**/*.tsx",
29
- "lib/**/*.ts",
30
- "lib/**/*.tsx",
31
25
  "shared/**/*.ts",
32
26
  "shared/**/*.tsx",
33
27
  "server/**/*.ts",
@@ -84,6 +84,7 @@ export default defineConfig(async ({ command }) => {
84
84
  }
85
85
 
86
86
  return {
87
+ root: path.resolve(__dirname, "client"),
87
88
  server: {
88
89
  host: "0.0.0.0",
89
90
  port: lockedPort,
@@ -92,7 +93,7 @@ export default defineConfig(async ({ command }) => {
92
93
  plugins: [
93
94
  react(),
94
95
  devServer({
95
- entry: "server/dev-app.ts",
96
+ entry: path.resolve(__dirname, "server/dev-app.ts"),
96
97
  adapter: nodeAdapter,
97
98
  exclude: [/^\/(?!api(?:\/|$)).*/, ...defaultOptions.exclude],
98
99
  }),
@@ -113,7 +114,7 @@ export default defineConfig(async ({ command }) => {
113
114
  ],
114
115
  resolve: {
115
116
  alias: {
116
- "@": path.resolve(__dirname, "."),
117
+ "@": path.resolve(__dirname, "client/src"),
117
118
  "@shared": path.resolve(__dirname, "shared"),
118
119
  },
119
120
  },
@@ -1,7 +0,0 @@
1
-
2
- ## 开发规则
3
-
4
- - `/.imagicma/port.json` 是初始化生成的锁定端口文件,禁止修改。
5
- - 禁止修改 `scripts/` 下的受保护启动文件:`imagicma-common.mjs`、`imagicma-guard.mjs`、`imagicma-dev.mjs`、`imagicma-start.mjs`。
6
- - 禁止修改 `package.json` 中 `scripts.dev` 与 `scripts.start`(以及对应 `predev`、`prestart`)命令。
7
- - 禁止直接执行 `vite` 或 `node dist/server/index.js` 启动项目;只能通过 `pnpm dev` / `pnpm start` 启动。
@@ -1,5 +0,0 @@
1
- {
2
- "port": 5001,
3
- "locked": true,
4
- "version": 1
5
- }
@@ -1,25 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react"
4
-
5
- import { cn } from "@/lib/utils"
6
-
7
- const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
8
- ({ className, type, ...props }, ref) => {
9
- // h-9 to match icon buttons and default buttons.
10
- return (
11
- <input
12
- type={type}
13
- className={cn(
14
- "flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
15
- className
16
- )}
17
- ref={ref}
18
- {...props}
19
- />
20
- )
21
- }
22
- )
23
- Input.displayName = "Input"
24
-
25
- export { Input }
@@ -1,24 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react"
4
-
5
- import { cn } from "@/lib/utils"
6
-
7
- const Textarea = React.forwardRef<
8
- HTMLTextAreaElement,
9
- React.ComponentProps<"textarea">
10
- >(({ className, ...props }, ref) => {
11
- return (
12
- <textarea
13
- className={cn(
14
- "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
15
- className
16
- )}
17
- ref={ref}
18
- {...props}
19
- />
20
- )
21
- })
22
- Textarea.displayName = "Textarea"
23
-
24
- export { Textarea }
File without changes