@lark-apaas/coding-templates 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -3
- package/template-vite-react/_gitignore +24 -0
- package/template-vite-react/client/index.html +13 -0
- package/template-vite-react/client/public/favicon.svg +1 -0
- package/template-vite-react/client/public/icons.svg +24 -0
- package/template-vite-react/client/src/api/index.ts +7 -0
- package/template-vite-react/client/src/app.tsx +17 -0
- package/{template-nextjs-static → template-vite-react/client}/src/components/header.tsx +5 -13
- package/template-vite-react/client/src/components/layout.tsx +13 -0
- package/template-vite-react/client/src/components/theme-provider.tsx +45 -0
- package/template-vite-react/client/src/components/ui/accordion.tsx +72 -0
- package/template-vite-react/client/src/components/ui/alert-dialog.tsx +187 -0
- package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/alert.tsx +15 -10
- package/template-vite-react/client/src/components/ui/aspect-ratio.tsx +22 -0
- package/template-vite-react/client/src/components/ui/avatar.tsx +109 -0
- package/template-vite-react/client/src/components/ui/badge.tsx +52 -0
- package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/breadcrumb.tsx +39 -23
- package/template-vite-react/client/src/components/ui/button.tsx +58 -0
- package/{template-nextjs-static → template-vite-react/client}/src/components/ui/calendar.tsx +43 -37
- package/template-vite-react/client/src/components/ui/card.tsx +103 -0
- package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/carousel.tsx +8 -7
- package/{template-nextjs-static → template-vite-react/client}/src/components/ui/chart.tsx +49 -35
- package/template-vite-react/client/src/components/ui/checkbox.tsx +29 -0
- package/template-vite-react/client/src/components/ui/collapsible.tsx +19 -0
- package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/command.tsx +40 -52
- package/template-vite-react/client/src/components/ui/context-menu.tsx +271 -0
- package/template-vite-react/client/src/components/ui/dialog.tsx +158 -0
- package/{template-nextjs-static → template-vite-react/client}/src/components/ui/drawer.tsx +9 -12
- package/template-vite-react/client/src/components/ui/dropdown-menu.tsx +268 -0
- package/template-vite-react/client/src/components/ui/hover-card.tsx +49 -0
- package/template-vite-react/client/src/components/ui/input-group.tsx +156 -0
- package/{template-nextjs-static → template-vite-react/client}/src/components/ui/input-otp.tsx +17 -7
- package/template-vite-react/client/src/components/ui/input.tsx +20 -0
- package/template-vite-react/client/src/components/ui/label.tsx +18 -0
- package/template-vite-react/client/src/components/ui/menubar.tsx +280 -0
- package/template-vite-react/client/src/components/ui/navigation-menu.tsx +168 -0
- package/{template-nextjs-static → template-vite-react/client}/src/components/ui/pagination.tsx +35 -32
- package/template-vite-react/client/src/components/ui/popover.tsx +90 -0
- package/template-vite-react/client/src/components/ui/progress.tsx +81 -0
- package/template-vite-react/client/src/components/ui/radio-group.tsx +38 -0
- package/template-vite-react/client/src/components/ui/resizable.tsx +48 -0
- package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/scroll-area.tsx +10 -13
- package/template-vite-react/client/src/components/ui/select.tsx +199 -0
- package/template-vite-react/client/src/components/ui/separator.tsx +25 -0
- package/template-vite-react/client/src/components/ui/sheet.tsx +138 -0
- package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/sidebar.tsx +156 -162
- package/{template-nextjs-static → template-vite-react/client}/src/components/ui/skeleton.tsx +1 -1
- package/template-vite-react/client/src/components/ui/slider.tsx +57 -0
- package/template-vite-react/client/src/components/ui/sonner.tsx +49 -0
- package/template-vite-react/client/src/components/ui/switch.tsx +30 -0
- package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/table.tsx +5 -5
- package/template-vite-react/client/src/components/ui/tabs.tsx +80 -0
- package/template-vite-react/client/src/components/ui/textarea.tsx +18 -0
- package/template-vite-react/client/src/components/ui/toggle-group.tsx +89 -0
- package/template-vite-react/client/src/components/ui/toggle.tsx +44 -0
- package/template-vite-react/client/src/components/ui/tooltip.tsx +64 -0
- package/template-vite-react/client/src/index.css +1 -0
- package/template-vite-react/client/src/main.tsx +13 -0
- package/template-vite-react/client/src/pages/home/index.tsx +12 -0
- package/template-vite-react/client/src/pages/not-found/index.tsx +11 -0
- package/template-vite-react/client/src/types/index.ts +1 -0
- package/{template-nextjs-static → template-vite-react}/components.json +2 -2
- package/template-vite-react/eslint.config.js +23 -0
- package/template-vite-react/package.json +58 -0
- package/template-vite-react/scripts/build.sh +40 -0
- package/template-vite-react/shared/types.ts +1 -0
- package/template-vite-react/tsconfig.app.json +33 -0
- package/template-vite-react/tsconfig.json +14 -0
- package/template-vite-react/tsconfig.node.json +26 -0
- package/template-vite-react/vite.config.ts +17 -0
- package/template-nextjs-fullstack/README.md +0 -169
- package/template-nextjs-fullstack/_env.local.example +0 -1
- package/template-nextjs-fullstack/_gitignore +0 -41
- package/template-nextjs-fullstack/components.json +0 -25
- package/template-nextjs-fullstack/drizzle.config.ts +0 -10
- package/template-nextjs-fullstack/eslint.config.js +0 -15
- package/template-nextjs-fullstack/next.config.ts +0 -5
- package/template-nextjs-fullstack/package.json +0 -85
- package/template-nextjs-fullstack/postcss.config.js +0 -8
- package/template-nextjs-fullstack/scripts/build.sh +0 -37
- package/template-nextjs-fullstack/src/app/favicon.ico +0 -0
- package/template-nextjs-fullstack/src/app/globals.css +0 -130
- package/template-nextjs-fullstack/src/app/layout.tsx +0 -24
- package/template-nextjs-fullstack/src/app/page.tsx +0 -69
- package/template-nextjs-fullstack/src/app/todos/actions.ts +0 -37
- package/template-nextjs-fullstack/src/app/todos/page.tsx +0 -26
- package/template-nextjs-fullstack/src/app/todos/todo-form.tsx +0 -27
- package/template-nextjs-fullstack/src/app/todos/todo-list.tsx +0 -44
- package/template-nextjs-fullstack/src/components/header.tsx +0 -32
- package/template-nextjs-fullstack/src/components/theme-provider.tsx +0 -8
- package/template-nextjs-fullstack/src/components/ui/README.md +0 -134
- package/template-nextjs-fullstack/src/components/ui/accordion.tsx +0 -66
- package/template-nextjs-fullstack/src/components/ui/alert-dialog.tsx +0 -157
- package/template-nextjs-fullstack/src/components/ui/aspect-ratio.tsx +0 -11
- package/template-nextjs-fullstack/src/components/ui/avatar.tsx +0 -53
- package/template-nextjs-fullstack/src/components/ui/badge.tsx +0 -42
- package/template-nextjs-fullstack/src/components/ui/button.tsx +0 -69
- package/template-nextjs-fullstack/src/components/ui/calendar.tsx +0 -213
- package/template-nextjs-fullstack/src/components/ui/card.tsx +0 -82
- package/template-nextjs-fullstack/src/components/ui/chart.tsx +0 -357
- package/template-nextjs-fullstack/src/components/ui/checkbox.tsx +0 -32
- package/template-nextjs-fullstack/src/components/ui/collapsible.tsx +0 -33
- package/template-nextjs-fullstack/src/components/ui/context-menu.tsx +0 -324
- package/template-nextjs-fullstack/src/components/ui/dialog.tsx +0 -143
- package/template-nextjs-fullstack/src/components/ui/drawer.tsx +0 -135
- package/template-nextjs-fullstack/src/components/ui/dropdown-menu.tsx +0 -329
- package/template-nextjs-fullstack/src/components/ui/hover-card.tsx +0 -44
- package/template-nextjs-fullstack/src/components/ui/input-group.tsx +0 -166
- package/template-nextjs-fullstack/src/components/ui/input-otp.tsx +0 -77
- package/template-nextjs-fullstack/src/components/ui/input.tsx +0 -21
- package/template-nextjs-fullstack/src/components/ui/label.tsx +0 -24
- package/template-nextjs-fullstack/src/components/ui/menubar.tsx +0 -348
- package/template-nextjs-fullstack/src/components/ui/navigation-menu.tsx +0 -168
- package/template-nextjs-fullstack/src/components/ui/pagination.tsx +0 -127
- package/template-nextjs-fullstack/src/components/ui/popover.tsx +0 -48
- package/template-nextjs-fullstack/src/components/ui/progress.tsx +0 -31
- package/template-nextjs-fullstack/src/components/ui/radio-group.tsx +0 -45
- package/template-nextjs-fullstack/src/components/ui/resizable.tsx +0 -56
- package/template-nextjs-fullstack/src/components/ui/select.tsx +0 -243
- package/template-nextjs-fullstack/src/components/ui/separator.tsx +0 -28
- package/template-nextjs-fullstack/src/components/ui/sheet.tsx +0 -139
- package/template-nextjs-fullstack/src/components/ui/skeleton.tsx +0 -13
- package/template-nextjs-fullstack/src/components/ui/slider.tsx +0 -87
- package/template-nextjs-fullstack/src/components/ui/sonner.tsx +0 -67
- package/template-nextjs-fullstack/src/components/ui/switch.tsx +0 -31
- package/template-nextjs-fullstack/src/components/ui/tabs.tsx +0 -66
- package/template-nextjs-fullstack/src/components/ui/textarea.tsx +0 -18
- package/template-nextjs-fullstack/src/components/ui/toggle-group.tsx +0 -83
- package/template-nextjs-fullstack/src/components/ui/toggle.tsx +0 -47
- package/template-nextjs-fullstack/src/components/ui/tooltip.tsx +0 -61
- package/template-nextjs-fullstack/src/db/index.ts +0 -8
- package/template-nextjs-fullstack/src/db/schema.ts +0 -11
- package/template-nextjs-fullstack/tailwind.config.ts +0 -10
- package/template-nextjs-fullstack/tsconfig.json +0 -34
- package/template-nextjs-static/README.md +0 -80
- package/template-nextjs-static/_gitignore +0 -41
- package/template-nextjs-static/eslint.config.js +0 -15
- package/template-nextjs-static/next.config.ts +0 -8
- package/template-nextjs-static/package.json +0 -77
- package/template-nextjs-static/postcss.config.js +0 -8
- package/template-nextjs-static/public/favicon.ico +0 -0
- package/template-nextjs-static/scripts/build.sh +0 -36
- package/template-nextjs-static/src/components/theme-provider.tsx +0 -6
- package/template-nextjs-static/src/components/ui/README.md +0 -134
- package/template-nextjs-static/src/components/ui/accordion.tsx +0 -66
- package/template-nextjs-static/src/components/ui/alert-dialog.tsx +0 -157
- package/template-nextjs-static/src/components/ui/alert.tsx +0 -71
- package/template-nextjs-static/src/components/ui/aspect-ratio.tsx +0 -11
- package/template-nextjs-static/src/components/ui/avatar.tsx +0 -53
- package/template-nextjs-static/src/components/ui/badge.tsx +0 -42
- package/template-nextjs-static/src/components/ui/breadcrumb.tsx +0 -109
- package/template-nextjs-static/src/components/ui/button-group.tsx +0 -83
- package/template-nextjs-static/src/components/ui/button.tsx +0 -69
- package/template-nextjs-static/src/components/ui/card.tsx +0 -82
- package/template-nextjs-static/src/components/ui/carousel.tsx +0 -241
- package/template-nextjs-static/src/components/ui/checkbox.tsx +0 -32
- package/template-nextjs-static/src/components/ui/collapsible.tsx +0 -33
- package/template-nextjs-static/src/components/ui/command.tsx +0 -208
- package/template-nextjs-static/src/components/ui/context-menu.tsx +0 -324
- package/template-nextjs-static/src/components/ui/dialog.tsx +0 -143
- package/template-nextjs-static/src/components/ui/dropdown-menu.tsx +0 -329
- package/template-nextjs-static/src/components/ui/empty.tsx +0 -104
- package/template-nextjs-static/src/components/ui/field.tsx +0 -248
- package/template-nextjs-static/src/components/ui/form.tsx +0 -167
- package/template-nextjs-static/src/components/ui/hover-card.tsx +0 -44
- package/template-nextjs-static/src/components/ui/icons/file-ae-colorful-icon.tsx +0 -21
- package/template-nextjs-static/src/components/ui/icons/file-ai-colorful-icon.tsx +0 -36
- package/template-nextjs-static/src/components/ui/icons/file-android-colorful-icon.tsx +0 -33
- package/template-nextjs-static/src/components/ui/icons/file-audio-colorful-icon.tsx +0 -21
- package/template-nextjs-static/src/components/ui/icons/file-code-colorful-icon.tsx +0 -28
- package/template-nextjs-static/src/components/ui/icons/file-csv-colorful-icon.tsx +0 -21
- package/template-nextjs-static/src/components/ui/icons/file-eml-colorful-icon.tsx +0 -29
- package/template-nextjs-static/src/components/ui/icons/file-ios-colorful-icon.tsx +0 -25
- package/template-nextjs-static/src/components/ui/icons/file-keynote-colorful-icon.tsx +0 -29
- package/template-nextjs-static/src/components/ui/icons/file-pages-colorful-icon.tsx +0 -29
- package/template-nextjs-static/src/components/ui/icons/file-ps-colorful-icon.tsx +0 -21
- package/template-nextjs-static/src/components/ui/icons/file-sketch-colorful-icon.tsx +0 -21
- package/template-nextjs-static/src/components/ui/icons/file-slide-colorful-icon.tsx +0 -21
- package/template-nextjs-static/src/components/ui/icons/file-vcf-colorful-icon.tsx +0 -29
- package/template-nextjs-static/src/components/ui/icons/file-wiki-excel-colorful-icon.tsx +0 -23
- package/template-nextjs-static/src/components/ui/icons/file-wiki-image-colorful-icon.tsx +0 -27
- package/template-nextjs-static/src/components/ui/icons/file-wiki-pdf-colorful-icon.tsx +0 -20
- package/template-nextjs-static/src/components/ui/icons/file-wiki-ppt-colorful-icon.tsx +0 -21
- package/template-nextjs-static/src/components/ui/icons/file-wiki-text-colorful-icon.tsx +0 -12
- package/template-nextjs-static/src/components/ui/icons/file-wiki-unknown-colorful-icon.tsx +0 -14
- package/template-nextjs-static/src/components/ui/icons/file-wiki-video-colorful-icon.tsx +0 -23
- package/template-nextjs-static/src/components/ui/icons/file-wiki-word-colorful-icon.tsx +0 -38
- package/template-nextjs-static/src/components/ui/icons/file-wiki-zip-colorful-icon.tsx +0 -21
- package/template-nextjs-static/src/components/ui/image.tsx +0 -183
- package/template-nextjs-static/src/components/ui/input-group.tsx +0 -166
- package/template-nextjs-static/src/components/ui/input.tsx +0 -21
- package/template-nextjs-static/src/components/ui/item.tsx +0 -193
- package/template-nextjs-static/src/components/ui/kbd.tsx +0 -28
- package/template-nextjs-static/src/components/ui/label.tsx +0 -24
- package/template-nextjs-static/src/components/ui/menubar.tsx +0 -348
- package/template-nextjs-static/src/components/ui/native-select.tsx +0 -48
- package/template-nextjs-static/src/components/ui/navigation-menu.tsx +0 -168
- package/template-nextjs-static/src/components/ui/popover.tsx +0 -48
- package/template-nextjs-static/src/components/ui/progress.tsx +0 -31
- package/template-nextjs-static/src/components/ui/radio-group.tsx +0 -45
- package/template-nextjs-static/src/components/ui/resizable.tsx +0 -56
- package/template-nextjs-static/src/components/ui/scroll-area.tsx +0 -58
- package/template-nextjs-static/src/components/ui/select.tsx +0 -243
- package/template-nextjs-static/src/components/ui/separator.tsx +0 -28
- package/template-nextjs-static/src/components/ui/sheet.tsx +0 -139
- package/template-nextjs-static/src/components/ui/sidebar.tsx +0 -727
- package/template-nextjs-static/src/components/ui/slider.tsx +0 -87
- package/template-nextjs-static/src/components/ui/sonner.tsx +0 -67
- package/template-nextjs-static/src/components/ui/spinner.tsx +0 -16
- package/template-nextjs-static/src/components/ui/streamdown.tsx +0 -186
- package/template-nextjs-static/src/components/ui/switch.tsx +0 -31
- package/template-nextjs-static/src/components/ui/table.tsx +0 -116
- package/template-nextjs-static/src/components/ui/tabs.tsx +0 -66
- package/template-nextjs-static/src/components/ui/textarea.tsx +0 -18
- package/template-nextjs-static/src/components/ui/toggle-group.tsx +0 -83
- package/template-nextjs-static/src/components/ui/toggle.tsx +0 -47
- package/template-nextjs-static/src/components/ui/tooltip.tsx +0 -61
- package/template-nextjs-static/src/hooks/use-mobile.ts +0 -19
- package/template-nextjs-static/src/lib/utils.ts +0 -6
- package/template-nextjs-static/src/pages/_app.tsx +0 -11
- package/template-nextjs-static/src/pages/_document.tsx +0 -13
- package/template-nextjs-static/src/pages/hello.tsx +0 -32
- package/template-nextjs-static/src/pages/index.tsx +0 -76
- package/template-nextjs-static/src/styles/globals.css +0 -143
- package/template-nextjs-static/tailwind.config.ts +0 -10
- package/template-nextjs-static/tsconfig.json +0 -34
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/button-group.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/empty.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/field.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/form.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-ae-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-ai-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-android-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-audio-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-code-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-csv-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-eml-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-ios-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-keynote-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-pages-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-ps-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-sketch-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-slide-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-vcf-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-wiki-excel-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-wiki-image-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-wiki-pdf-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-wiki-ppt-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-wiki-text-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-wiki-unknown-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-wiki-video-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-wiki-word-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/icons/file-wiki-zip-colorful-icon.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/image.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/item.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/kbd.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/native-select.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/spinner.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/components/ui/streamdown.tsx +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/hooks/use-mobile.ts +0 -0
- /package/{template-nextjs-fullstack → template-vite-react/client}/src/lib/utils.ts +0 -0
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
# Next.js 全栈模板
|
|
2
|
-
|
|
3
|
-
Next.js App Router + Drizzle ORM + PostgreSQL 全栈模板,支持 Server Actions、SSR、API Routes。
|
|
4
|
-
|
|
5
|
-
## 快速开始
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# 1. 安装依赖
|
|
9
|
-
npm install
|
|
10
|
-
|
|
11
|
-
# 2. 配置数据库(修改 .env.local 中的 DATABASE_URL)
|
|
12
|
-
cp .env.local.example .env.local
|
|
13
|
-
|
|
14
|
-
# 3. 初始化数据库表
|
|
15
|
-
npm run db:push
|
|
16
|
-
|
|
17
|
-
# 4. 启动开发服务器
|
|
18
|
-
npm run dev
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
打开 http://localhost:3000 查看效果。
|
|
22
|
-
|
|
23
|
-
## 命令
|
|
24
|
-
|
|
25
|
-
| 命令 | 说明 |
|
|
26
|
-
|---|---|
|
|
27
|
-
| `npm run dev` | 启动开发服务器 |
|
|
28
|
-
| `npm run build` | 生产构建 |
|
|
29
|
-
| `npm run start` | 启动生产服务 |
|
|
30
|
-
| `npm run lint` | 运行 ESLint |
|
|
31
|
-
| `npm run db:generate` | 生成 Drizzle 迁移文件 |
|
|
32
|
-
| `npm run db:migrate` | 执行数据库迁移 |
|
|
33
|
-
| `npm run db:push` | 推送 schema 到数据库(开发用) |
|
|
34
|
-
| `npm run db:studio` | 打开 Drizzle Studio |
|
|
35
|
-
|
|
36
|
-
## 独立部署(Docker / FaaS 容器模式)
|
|
37
|
-
|
|
38
|
-
### 1. 开启 standalone 模式
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
// next.config.ts
|
|
42
|
-
import type { NextConfig } from "next";
|
|
43
|
-
|
|
44
|
-
const nextConfig: NextConfig = {
|
|
45
|
-
output: "standalone",
|
|
46
|
-
assetPrefix: "https://cdn.example.com", // 静态资源 CDN 地址
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export default nextConfig;
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### 2. 构建
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
npm run build
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
产出 `.next/standalone/` 目录,包含:
|
|
59
|
-
- `server.js` — 服务入口,`node server.js` 直接启动
|
|
60
|
-
- `node_modules/` — 仅运行时依赖(tree-shaking 后,远小于完整 node_modules)
|
|
61
|
-
- `.next/server/` — SSR 产物
|
|
62
|
-
|
|
63
|
-
### 3. Dockerfile
|
|
64
|
-
|
|
65
|
-
```dockerfile
|
|
66
|
-
FROM node:20-alpine
|
|
67
|
-
WORKDIR /app
|
|
68
|
-
|
|
69
|
-
# 复制 standalone 产出
|
|
70
|
-
COPY .next/standalone ./
|
|
71
|
-
# 静态资源(如果不走 CDN 则需要复制)
|
|
72
|
-
COPY .next/static ./.next/static
|
|
73
|
-
COPY public ./public
|
|
74
|
-
|
|
75
|
-
ENV NODE_ENV=production
|
|
76
|
-
ENV PORT=3000
|
|
77
|
-
EXPOSE 3000
|
|
78
|
-
|
|
79
|
-
CMD ["node", "server.js"]
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
docker build -t my-app .
|
|
84
|
-
docker run -p 3000:3000 \
|
|
85
|
-
-e DATABASE_URL="postgresql://user:pass@host:5432/db" \
|
|
86
|
-
my-app
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
镜像体积约 100-150MB,启动时间 1-2 秒。
|
|
90
|
-
|
|
91
|
-
### 4. 部署架构
|
|
92
|
-
|
|
93
|
-
```
|
|
94
|
-
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐
|
|
95
|
-
│ 浏览器 │────→│ Nginx / 网关 │────→│ FaaS 容器 │
|
|
96
|
-
│ │ │ │ │ server.js │
|
|
97
|
-
│ │ │ 路由分发: │ │ (standalone)│
|
|
98
|
-
│ │ │ /*.html → 容器 │ │ │
|
|
99
|
-
│ │ │ │ │ ↓ │
|
|
100
|
-
│ │ └──────────────────┘ │ PostgreSQL │
|
|
101
|
-
│ │ │ └─────────────┘
|
|
102
|
-
│ │ │
|
|
103
|
-
│ │ ┌────────↓─────────┐
|
|
104
|
-
│ │←────│ CDN │
|
|
105
|
-
│ │ │ _next/static/* │
|
|
106
|
-
│ │ │ (JS/CSS/字体) │
|
|
107
|
-
│ │ └──────────────────┘
|
|
108
|
-
│ │
|
|
109
|
-
│ │ ┌──────────────────┐
|
|
110
|
-
│ │←────│ TOS │
|
|
111
|
-
│ │ │ 图片资源 │
|
|
112
|
-
│ │ │ (独立权限控制) │
|
|
113
|
-
│ │ └──────────────────┘
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
| 资源类型 | 部署位置 | 说明 |
|
|
117
|
-
|---|---|---|
|
|
118
|
-
| HTML / SSR / API | FaaS 容器 | standalone server.js 处理 |
|
|
119
|
-
| JS / CSS / 字体 | CDN | 通过 `assetPrefix` 配置 |
|
|
120
|
-
| 图片 | TOS | 通过自定义 Image Loader |
|
|
121
|
-
| 数据库 | PostgreSQL | 通过 `DATABASE_URL` 环境变量 |
|
|
122
|
-
|
|
123
|
-
### 5. 图片走 TOS(可选)
|
|
124
|
-
|
|
125
|
-
如果图片需要部署到独立的 TOS(对象存储),配置自定义 Image Loader:
|
|
126
|
-
|
|
127
|
-
```ts
|
|
128
|
-
// next.config.ts
|
|
129
|
-
const nextConfig: NextConfig = {
|
|
130
|
-
output: "standalone",
|
|
131
|
-
assetPrefix: "https://cdn.example.com",
|
|
132
|
-
images: {
|
|
133
|
-
loader: "custom",
|
|
134
|
-
loaderFile: "./src/lib/image-loader.ts",
|
|
135
|
-
},
|
|
136
|
-
};
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
```ts
|
|
140
|
-
// src/lib/image-loader.ts
|
|
141
|
-
export default function tosLoader({
|
|
142
|
-
src,
|
|
143
|
-
width,
|
|
144
|
-
quality,
|
|
145
|
-
}: {
|
|
146
|
-
src: string;
|
|
147
|
-
width: number;
|
|
148
|
-
quality?: number;
|
|
149
|
-
}) {
|
|
150
|
-
return `https://tos.example.com${src}?w=${width}&q=${quality || 75}`;
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### 6. 环境变量
|
|
155
|
-
|
|
156
|
-
| 变量 | 说明 | 示例 |
|
|
157
|
-
|---|---|---|
|
|
158
|
-
| `DATABASE_URL` | PostgreSQL 连接地址 | `postgresql://user:pass@host:5432/db` |
|
|
159
|
-
| `PORT` | 服务端口(默认 3000) | `3000` |
|
|
160
|
-
| `HOSTNAME` | 监听地址(容器中建议 0.0.0.0) | `0.0.0.0` |
|
|
161
|
-
|
|
162
|
-
## 技术栈
|
|
163
|
-
|
|
164
|
-
- Next.js 16(App Router、SSR、Server Actions)
|
|
165
|
-
- React 19、TypeScript 5
|
|
166
|
-
- Tailwind CSS 4 + shadcn/ui(base-nova 风格、lucide 图标)
|
|
167
|
-
- Drizzle ORM + PostgreSQL
|
|
168
|
-
- Zod(数据校验)
|
|
169
|
-
- next-themes(暗色模式)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/openclaw
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
2
|
-
|
|
3
|
-
# dependencies
|
|
4
|
-
/node_modules
|
|
5
|
-
/.pnp
|
|
6
|
-
.pnp.*
|
|
7
|
-
.yarn/*
|
|
8
|
-
!.yarn/patches
|
|
9
|
-
!.yarn/plugins
|
|
10
|
-
!.yarn/releases
|
|
11
|
-
!.yarn/versions
|
|
12
|
-
|
|
13
|
-
# testing
|
|
14
|
-
/coverage
|
|
15
|
-
|
|
16
|
-
# next.js
|
|
17
|
-
/.next/
|
|
18
|
-
/out/
|
|
19
|
-
|
|
20
|
-
# production
|
|
21
|
-
/build
|
|
22
|
-
|
|
23
|
-
# misc
|
|
24
|
-
.DS_Store
|
|
25
|
-
*.pem
|
|
26
|
-
|
|
27
|
-
# debug
|
|
28
|
-
npm-debug.log*
|
|
29
|
-
yarn-debug.log*
|
|
30
|
-
yarn-error.log*
|
|
31
|
-
.pnpm-debug.log*
|
|
32
|
-
|
|
33
|
-
# env files (can opt-in for committing if needed)
|
|
34
|
-
.env*
|
|
35
|
-
|
|
36
|
-
# vercel
|
|
37
|
-
.vercel
|
|
38
|
-
|
|
39
|
-
# typescript
|
|
40
|
-
*.tsbuildinfo
|
|
41
|
-
next-env.d.ts
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
-
"style": "base-nova",
|
|
4
|
-
"rsc": true,
|
|
5
|
-
"tsx": true,
|
|
6
|
-
"tailwind": {
|
|
7
|
-
"config": "tailwind.config.ts",
|
|
8
|
-
"css": "src/app/globals.css",
|
|
9
|
-
"baseColor": "neutral",
|
|
10
|
-
"cssVariables": true,
|
|
11
|
-
"prefix": ""
|
|
12
|
-
},
|
|
13
|
-
"iconLibrary": "lucide",
|
|
14
|
-
"rtl": false,
|
|
15
|
-
"aliases": {
|
|
16
|
-
"components": "@/components",
|
|
17
|
-
"utils": "@/lib/utils",
|
|
18
|
-
"ui": "@/components/ui",
|
|
19
|
-
"lib": "@/lib",
|
|
20
|
-
"hooks": "@/hooks"
|
|
21
|
-
},
|
|
22
|
-
"menuColor": "default",
|
|
23
|
-
"menuAccent": "subtle",
|
|
24
|
-
"registries": {}
|
|
25
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
const js = require('@eslint/js');
|
|
2
|
-
const tseslint = require('typescript-eslint');
|
|
3
|
-
|
|
4
|
-
module.exports = tseslint.config(
|
|
5
|
-
{ ignores: ['.next', 'out', 'node_modules'] },
|
|
6
|
-
js.configs.recommended,
|
|
7
|
-
...tseslint.configs.recommended,
|
|
8
|
-
{
|
|
9
|
-
files: ['src/**/*.{ts,tsx}'],
|
|
10
|
-
rules: {
|
|
11
|
-
'@typescript-eslint/no-unused-vars': 'warn',
|
|
12
|
-
'@typescript-eslint/no-unused-expressions': 'off',
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
);
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "{{projectName}}",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"mclaw": {
|
|
6
|
-
"stack": "nextjs",
|
|
7
|
-
"stackVersion": "0.1.0"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"dev": "next dev",
|
|
11
|
-
"build": "bash scripts/build.sh",
|
|
12
|
-
"start": "next start",
|
|
13
|
-
"lint": "eslint src",
|
|
14
|
-
"db:generate": "drizzle-kit generate",
|
|
15
|
-
"db:migrate": "drizzle-kit migrate",
|
|
16
|
-
"db:push": "drizzle-kit push",
|
|
17
|
-
"db:studio": "drizzle-kit studio"
|
|
18
|
-
},
|
|
19
|
-
"dependencies": {
|
|
20
|
-
"@base-ui/react": "^1.3.0",
|
|
21
|
-
"@radix-ui/react-accordion": "^1.2.12",
|
|
22
|
-
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
23
|
-
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
|
24
|
-
"@radix-ui/react-avatar": "^1.1.10",
|
|
25
|
-
"@radix-ui/react-checkbox": "^1.3.3",
|
|
26
|
-
"@radix-ui/react-collapsible": "^1.1.12",
|
|
27
|
-
"@radix-ui/react-context-menu": "^2.2.16",
|
|
28
|
-
"@radix-ui/react-dialog": "^1.1.15",
|
|
29
|
-
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
30
|
-
"@radix-ui/react-hover-card": "^1.1.15",
|
|
31
|
-
"@radix-ui/react-label": "^2.1.7",
|
|
32
|
-
"@radix-ui/react-menubar": "^1.1.16",
|
|
33
|
-
"@radix-ui/react-navigation-menu": "^1.2.14",
|
|
34
|
-
"@radix-ui/react-popover": "^1.1.15",
|
|
35
|
-
"@radix-ui/react-progress": "^1.1.7",
|
|
36
|
-
"@radix-ui/react-radio-group": "^1.3.8",
|
|
37
|
-
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
38
|
-
"@radix-ui/react-select": "^2.2.6",
|
|
39
|
-
"@radix-ui/react-separator": "^1.1.7",
|
|
40
|
-
"@radix-ui/react-slider": "^1.3.6",
|
|
41
|
-
"@radix-ui/react-slot": "^1.2.3",
|
|
42
|
-
"@radix-ui/react-switch": "^1.2.6",
|
|
43
|
-
"@radix-ui/react-tabs": "^1.1.13",
|
|
44
|
-
"@radix-ui/react-toggle": "^1.1.10",
|
|
45
|
-
"@radix-ui/react-toggle-group": "^1.1.11",
|
|
46
|
-
"@radix-ui/react-tooltip": "^1.2.8",
|
|
47
|
-
"class-variance-authority": "^0.7.1",
|
|
48
|
-
"clsx": "^2.1.1",
|
|
49
|
-
"cmdk": "^1.1.1",
|
|
50
|
-
"drizzle-orm": "^0.45.1",
|
|
51
|
-
"embla-carousel-react": "^8.6.0",
|
|
52
|
-
"es-toolkit": "^1.43.0",
|
|
53
|
-
"framer-motion": "^12.36.0",
|
|
54
|
-
"input-otp": "^1.4.2",
|
|
55
|
-
"lucide-react": "^0.577.0",
|
|
56
|
-
"next": "16.1.6",
|
|
57
|
-
"next-themes": "^0.4.6",
|
|
58
|
-
"postgres": "^3.4.8",
|
|
59
|
-
"react": "19.2.3",
|
|
60
|
-
"react-day-picker": "^9.11.1",
|
|
61
|
-
"react-dom": "19.2.3",
|
|
62
|
-
"react-hook-form": "^7.65.0",
|
|
63
|
-
"react-resizable-panels": "^3.0.6",
|
|
64
|
-
"recharts": "^2.15.4",
|
|
65
|
-
"shadcn": "^4.0.8",
|
|
66
|
-
"sonner": "^2.0.7",
|
|
67
|
-
"streamdown": "^1.6.10",
|
|
68
|
-
"tailwind-merge": "^3.5.0",
|
|
69
|
-
"tw-animate-css": "^1.4.0",
|
|
70
|
-
"vaul": "^1.1.2",
|
|
71
|
-
"zod": "^4.3.6"
|
|
72
|
-
},
|
|
73
|
-
"devDependencies": {
|
|
74
|
-
"@eslint/js": "^9",
|
|
75
|
-
"@tailwindcss/postcss": "^4",
|
|
76
|
-
"@types/node": "^20",
|
|
77
|
-
"@types/react": "^19",
|
|
78
|
-
"@types/react-dom": "^19",
|
|
79
|
-
"drizzle-kit": "^0.31.9",
|
|
80
|
-
"eslint": "^9",
|
|
81
|
-
"tailwindcss": "^4",
|
|
82
|
-
"typescript": "^5",
|
|
83
|
-
"typescript-eslint": "^8"
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
set -e
|
|
3
|
-
|
|
4
|
-
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
-
OUTPUT="$ROOT/dist/output"
|
|
6
|
-
OUTPUT_RESOURCE="$ROOT/dist/output_resource"
|
|
7
|
-
|
|
8
|
-
# 清理
|
|
9
|
-
rm -rf "$ROOT/dist"
|
|
10
|
-
|
|
11
|
-
# 1. Next.js 构建 → .next/
|
|
12
|
-
npx next build
|
|
13
|
-
|
|
14
|
-
# 2. standalone → dist/output/
|
|
15
|
-
mkdir -p "$OUTPUT"
|
|
16
|
-
cp -r "$ROOT/.next/standalone/." "$OUTPUT/"
|
|
17
|
-
|
|
18
|
-
# 复制 public/ 到 standalone
|
|
19
|
-
if [ -d "$ROOT/public" ]; then
|
|
20
|
-
cp -r "$ROOT/public" "$OUTPUT/public"
|
|
21
|
-
fi
|
|
22
|
-
|
|
23
|
-
# 3. static/ → dist/output_resource/(JS/CSS/字体,上传到 CDN)
|
|
24
|
-
if [ -d "$ROOT/.next/static" ]; then
|
|
25
|
-
mkdir -p "$OUTPUT_RESOURCE/_next"
|
|
26
|
-
cp -r "$ROOT/.next/static" "$OUTPUT_RESOURCE/_next/"
|
|
27
|
-
fi
|
|
28
|
-
|
|
29
|
-
# 复制 .next/static 到 standalone
|
|
30
|
-
if [ -d "$ROOT/.next/static" ]; then
|
|
31
|
-
mkdir -p "$OUTPUT/.next"
|
|
32
|
-
cp -r "$ROOT/.next/static" "$OUTPUT/.next/"
|
|
33
|
-
fi
|
|
34
|
-
|
|
35
|
-
echo "Build complete"
|
|
36
|
-
echo " Standalone → dist/output/"
|
|
37
|
-
[ -d "$OUTPUT_RESOURCE" ] && echo " Resource → dist/output_resource/"
|
|
Binary file
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
2
|
-
@import "tw-animate-css";
|
|
3
|
-
@import "shadcn/tailwind.css";
|
|
4
|
-
@config "../../tailwind.config.ts";
|
|
5
|
-
|
|
6
|
-
@custom-variant dark (&:is(.dark *));
|
|
7
|
-
|
|
8
|
-
@theme inline {
|
|
9
|
-
--color-background: var(--background);
|
|
10
|
-
--color-foreground: var(--foreground);
|
|
11
|
-
--font-sans: var(--font-sans);
|
|
12
|
-
--font-mono: var(--font-geist-mono);
|
|
13
|
-
--color-sidebar-ring: var(--sidebar-ring);
|
|
14
|
-
--color-sidebar-border: var(--sidebar-border);
|
|
15
|
-
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
16
|
-
--color-sidebar-accent: var(--sidebar-accent);
|
|
17
|
-
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
18
|
-
--color-sidebar-primary: var(--sidebar-primary);
|
|
19
|
-
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
20
|
-
--color-sidebar: var(--sidebar);
|
|
21
|
-
--color-chart-5: var(--chart-5);
|
|
22
|
-
--color-chart-4: var(--chart-4);
|
|
23
|
-
--color-chart-3: var(--chart-3);
|
|
24
|
-
--color-chart-2: var(--chart-2);
|
|
25
|
-
--color-chart-1: var(--chart-1);
|
|
26
|
-
--color-ring: var(--ring);
|
|
27
|
-
--color-input: var(--input);
|
|
28
|
-
--color-border: var(--border);
|
|
29
|
-
--color-destructive: var(--destructive);
|
|
30
|
-
--color-accent-foreground: var(--accent-foreground);
|
|
31
|
-
--color-accent: var(--accent);
|
|
32
|
-
--color-muted-foreground: var(--muted-foreground);
|
|
33
|
-
--color-muted: var(--muted);
|
|
34
|
-
--color-secondary-foreground: var(--secondary-foreground);
|
|
35
|
-
--color-secondary: var(--secondary);
|
|
36
|
-
--color-primary-foreground: var(--primary-foreground);
|
|
37
|
-
--color-primary: var(--primary);
|
|
38
|
-
--color-popover-foreground: var(--popover-foreground);
|
|
39
|
-
--color-popover: var(--popover);
|
|
40
|
-
--color-card-foreground: var(--card-foreground);
|
|
41
|
-
--color-card: var(--card);
|
|
42
|
-
--radius-sm: calc(var(--radius) * 0.6);
|
|
43
|
-
--radius-md: calc(var(--radius) * 0.8);
|
|
44
|
-
--radius-lg: var(--radius);
|
|
45
|
-
--radius-xl: calc(var(--radius) * 1.4);
|
|
46
|
-
--radius-2xl: calc(var(--radius) * 1.8);
|
|
47
|
-
--radius-3xl: calc(var(--radius) * 2.2);
|
|
48
|
-
--radius-4xl: calc(var(--radius) * 2.6);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
:root {
|
|
52
|
-
--background: oklch(1 0 0);
|
|
53
|
-
--foreground: oklch(0.145 0 0);
|
|
54
|
-
--card: oklch(1 0 0);
|
|
55
|
-
--card-foreground: oklch(0.145 0 0);
|
|
56
|
-
--popover: oklch(1 0 0);
|
|
57
|
-
--popover-foreground: oklch(0.145 0 0);
|
|
58
|
-
--primary: oklch(0.205 0 0);
|
|
59
|
-
--primary-foreground: oklch(0.985 0 0);
|
|
60
|
-
--secondary: oklch(0.97 0 0);
|
|
61
|
-
--secondary-foreground: oklch(0.205 0 0);
|
|
62
|
-
--muted: oklch(0.97 0 0);
|
|
63
|
-
--muted-foreground: oklch(0.556 0 0);
|
|
64
|
-
--accent: oklch(0.97 0 0);
|
|
65
|
-
--accent-foreground: oklch(0.205 0 0);
|
|
66
|
-
--destructive: oklch(0.577 0.245 27.325);
|
|
67
|
-
--border: oklch(0.922 0 0);
|
|
68
|
-
--input: oklch(0.922 0 0);
|
|
69
|
-
--ring: oklch(0.708 0 0);
|
|
70
|
-
--chart-1: oklch(0.809 0.105 251.813);
|
|
71
|
-
--chart-2: oklch(0.623 0.214 259.815);
|
|
72
|
-
--chart-3: oklch(0.546 0.245 262.881);
|
|
73
|
-
--chart-4: oklch(0.488 0.243 264.376);
|
|
74
|
-
--chart-5: oklch(0.424 0.199 265.638);
|
|
75
|
-
--radius: 0.625rem;
|
|
76
|
-
--sidebar: oklch(0.985 0 0);
|
|
77
|
-
--sidebar-foreground: oklch(0.145 0 0);
|
|
78
|
-
--sidebar-primary: oklch(0.205 0 0);
|
|
79
|
-
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
80
|
-
--sidebar-accent: oklch(0.97 0 0);
|
|
81
|
-
--sidebar-accent-foreground: oklch(0.205 0 0);
|
|
82
|
-
--sidebar-border: oklch(0.922 0 0);
|
|
83
|
-
--sidebar-ring: oklch(0.708 0 0);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.dark {
|
|
87
|
-
--background: oklch(0.145 0 0);
|
|
88
|
-
--foreground: oklch(0.985 0 0);
|
|
89
|
-
--card: oklch(0.205 0 0);
|
|
90
|
-
--card-foreground: oklch(0.985 0 0);
|
|
91
|
-
--popover: oklch(0.205 0 0);
|
|
92
|
-
--popover-foreground: oklch(0.985 0 0);
|
|
93
|
-
--primary: oklch(0.922 0 0);
|
|
94
|
-
--primary-foreground: oklch(0.205 0 0);
|
|
95
|
-
--secondary: oklch(0.269 0 0);
|
|
96
|
-
--secondary-foreground: oklch(0.985 0 0);
|
|
97
|
-
--muted: oklch(0.269 0 0);
|
|
98
|
-
--muted-foreground: oklch(0.708 0 0);
|
|
99
|
-
--accent: oklch(0.269 0 0);
|
|
100
|
-
--accent-foreground: oklch(0.985 0 0);
|
|
101
|
-
--destructive: oklch(0.704 0.191 22.216);
|
|
102
|
-
--border: oklch(1 0 0 / 10%);
|
|
103
|
-
--input: oklch(1 0 0 / 15%);
|
|
104
|
-
--ring: oklch(0.556 0 0);
|
|
105
|
-
--chart-1: oklch(0.809 0.105 251.813);
|
|
106
|
-
--chart-2: oklch(0.623 0.214 259.815);
|
|
107
|
-
--chart-3: oklch(0.546 0.245 262.881);
|
|
108
|
-
--chart-4: oklch(0.488 0.243 264.376);
|
|
109
|
-
--chart-5: oklch(0.424 0.199 265.638);
|
|
110
|
-
--sidebar: oklch(0.205 0 0);
|
|
111
|
-
--sidebar-foreground: oklch(0.985 0 0);
|
|
112
|
-
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
113
|
-
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
114
|
-
--sidebar-accent: oklch(0.269 0 0);
|
|
115
|
-
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
116
|
-
--sidebar-border: oklch(1 0 0 / 10%);
|
|
117
|
-
--sidebar-ring: oklch(0.556 0 0);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
@layer base {
|
|
121
|
-
* {
|
|
122
|
-
@apply border-border outline-ring/50;
|
|
123
|
-
}
|
|
124
|
-
body {
|
|
125
|
-
@apply bg-background text-foreground;
|
|
126
|
-
}
|
|
127
|
-
html {
|
|
128
|
-
@apply font-sans;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { Metadata } from "next";
|
|
2
|
-
import { Geist, Geist_Mono } from "next/font/google";
|
|
3
|
-
import "./globals.css";
|
|
4
|
-
import { ThemeProvider } from "@/components/theme-provider";
|
|
5
|
-
|
|
6
|
-
const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"] });
|
|
7
|
-
const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"] });
|
|
8
|
-
|
|
9
|
-
export const metadata: Metadata = {
|
|
10
|
-
title: "OpenClaw Fullstack",
|
|
11
|
-
description: "Next.js Fullstack Template with Drizzle + PostgreSQL",
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
15
|
-
return (
|
|
16
|
-
<html lang="zh" suppressHydrationWarning>
|
|
17
|
-
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
|
18
|
-
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
|
|
19
|
-
{children}
|
|
20
|
-
</ThemeProvider>
|
|
21
|
-
</body>
|
|
22
|
-
</html>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { Button } from "@/components/ui/button";
|
|
2
|
-
import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
3
|
-
import { Badge } from "@/components/ui/badge";
|
|
4
|
-
import { Header } from "@/components/header";
|
|
5
|
-
import { Database, Zap, Shield } from "lucide-react";
|
|
6
|
-
import Link from "next/link";
|
|
7
|
-
|
|
8
|
-
export default function Home() {
|
|
9
|
-
return (
|
|
10
|
-
<div className="min-h-screen bg-background">
|
|
11
|
-
<Header />
|
|
12
|
-
<main>
|
|
13
|
-
<section className="container mx-auto px-4 py-24 text-center">
|
|
14
|
-
<Badge variant="secondary" className="mb-4">Next.js Fullstack</Badge>
|
|
15
|
-
<h1 className="text-4xl font-bold tracking-tight sm:text-6xl mb-6">
|
|
16
|
-
全栈应用模版
|
|
17
|
-
</h1>
|
|
18
|
-
<p className="text-lg text-muted-foreground max-w-2xl mx-auto mb-8">
|
|
19
|
-
基于 Next.js + Drizzle ORM + PostgreSQL 的全栈模版,Server Actions 驱动数据变更,为 AI 协作开发而生。
|
|
20
|
-
</p>
|
|
21
|
-
<div className="flex gap-4 justify-center">
|
|
22
|
-
<Link href="/todos">
|
|
23
|
-
<Button size="lg">查看 Todos 示例</Button>
|
|
24
|
-
</Link>
|
|
25
|
-
<Button size="lg" variant="outline">了解更多</Button>
|
|
26
|
-
</div>
|
|
27
|
-
</section>
|
|
28
|
-
|
|
29
|
-
<section className="container mx-auto px-4 py-16">
|
|
30
|
-
<div className="grid gap-6 md:grid-cols-3">
|
|
31
|
-
<Card>
|
|
32
|
-
<CardHeader>
|
|
33
|
-
<Database className="h-10 w-10 mb-2 text-primary" />
|
|
34
|
-
<CardTitle>类型安全数据库</CardTitle>
|
|
35
|
-
<CardDescription>
|
|
36
|
-
Drizzle ORM 提供端到端类型安全,schema 即代码,迁移自动生成。
|
|
37
|
-
</CardDescription>
|
|
38
|
-
</CardHeader>
|
|
39
|
-
</Card>
|
|
40
|
-
<Card>
|
|
41
|
-
<CardHeader>
|
|
42
|
-
<Zap className="h-10 w-10 mb-2 text-primary" />
|
|
43
|
-
<CardTitle>Server Actions</CardTitle>
|
|
44
|
-
<CardDescription>
|
|
45
|
-
数据变更直接写在服务端函数里,无需手写 API 路由,AI 生成代码更高效。
|
|
46
|
-
</CardDescription>
|
|
47
|
-
</CardHeader>
|
|
48
|
-
</Card>
|
|
49
|
-
<Card>
|
|
50
|
-
<CardHeader>
|
|
51
|
-
<Shield className="h-10 w-10 mb-2 text-primary" />
|
|
52
|
-
<CardTitle>数据校验</CardTitle>
|
|
53
|
-
<CardDescription>
|
|
54
|
-
Zod schema 校验贯穿前后端,类型安全从表单到数据库全链路保障。
|
|
55
|
-
</CardDescription>
|
|
56
|
-
</CardHeader>
|
|
57
|
-
</Card>
|
|
58
|
-
</div>
|
|
59
|
-
</section>
|
|
60
|
-
|
|
61
|
-
<footer className="border-t py-8">
|
|
62
|
-
<div className="container mx-auto px-4 text-center text-sm text-muted-foreground">
|
|
63
|
-
OpenClaw Template — Built for Vibe Coding
|
|
64
|
-
</div>
|
|
65
|
-
</footer>
|
|
66
|
-
</main>
|
|
67
|
-
</div>
|
|
68
|
-
);
|
|
69
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"use server";
|
|
2
|
-
|
|
3
|
-
import { db } from "@/db";
|
|
4
|
-
import { todos } from "@/db/schema";
|
|
5
|
-
import { eq } from "drizzle-orm";
|
|
6
|
-
import { revalidatePath } from "next/cache";
|
|
7
|
-
import { z } from "zod";
|
|
8
|
-
|
|
9
|
-
const createTodoSchema = z.object({
|
|
10
|
-
title: z.string().min(1, "标题不能为空").max(200, "标题不能超过200字"),
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
export async function createTodo(formData: FormData) {
|
|
14
|
-
const parsed = createTodoSchema.safeParse({
|
|
15
|
-
title: formData.get("title"),
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
if (!parsed.success) {
|
|
19
|
-
return { error: parsed.error.flatten().fieldErrors.title?.[0] };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
await db.insert(todos).values({ title: parsed.data.title });
|
|
23
|
-
revalidatePath("/todos");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export async function toggleTodo(id: number) {
|
|
27
|
-
const [todo] = await db.select().from(todos).where(eq(todos.id, id));
|
|
28
|
-
if (todo) {
|
|
29
|
-
await db.update(todos).set({ completed: !todo.completed }).where(eq(todos.id, id));
|
|
30
|
-
}
|
|
31
|
-
revalidatePath("/todos");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export async function deleteTodo(id: number) {
|
|
35
|
-
await db.delete(todos).where(eq(todos.id, id));
|
|
36
|
-
revalidatePath("/todos");
|
|
37
|
-
}
|