@lark-apaas/coding-templates 0.1.0

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 (216) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +128 -0
  3. package/meta.json +22 -0
  4. package/package.json +22 -0
  5. package/template-html/README.md +148 -0
  6. package/template-html/_gitignore +2 -0
  7. package/template-html/index.html +22 -0
  8. package/template-html/package.json +12 -0
  9. package/template-html/routes.json +1 -0
  10. package/template-html/scripts/build.sh +31 -0
  11. package/template-nextjs-fullstack/README.md +169 -0
  12. package/template-nextjs-fullstack/_env.local.example +1 -0
  13. package/template-nextjs-fullstack/_gitignore +41 -0
  14. package/template-nextjs-fullstack/components.json +25 -0
  15. package/template-nextjs-fullstack/drizzle.config.ts +10 -0
  16. package/template-nextjs-fullstack/eslint.config.js +15 -0
  17. package/template-nextjs-fullstack/next.config.ts +5 -0
  18. package/template-nextjs-fullstack/package.json +85 -0
  19. package/template-nextjs-fullstack/postcss.config.js +8 -0
  20. package/template-nextjs-fullstack/scripts/build.sh +37 -0
  21. package/template-nextjs-fullstack/src/app/favicon.ico +0 -0
  22. package/template-nextjs-fullstack/src/app/globals.css +130 -0
  23. package/template-nextjs-fullstack/src/app/layout.tsx +24 -0
  24. package/template-nextjs-fullstack/src/app/page.tsx +69 -0
  25. package/template-nextjs-fullstack/src/app/todos/actions.ts +37 -0
  26. package/template-nextjs-fullstack/src/app/todos/page.tsx +26 -0
  27. package/template-nextjs-fullstack/src/app/todos/todo-form.tsx +27 -0
  28. package/template-nextjs-fullstack/src/app/todos/todo-list.tsx +44 -0
  29. package/template-nextjs-fullstack/src/components/header.tsx +32 -0
  30. package/template-nextjs-fullstack/src/components/theme-provider.tsx +8 -0
  31. package/template-nextjs-fullstack/src/components/ui/README.md +134 -0
  32. package/template-nextjs-fullstack/src/components/ui/accordion.tsx +66 -0
  33. package/template-nextjs-fullstack/src/components/ui/alert-dialog.tsx +157 -0
  34. package/template-nextjs-fullstack/src/components/ui/alert.tsx +71 -0
  35. package/template-nextjs-fullstack/src/components/ui/aspect-ratio.tsx +11 -0
  36. package/template-nextjs-fullstack/src/components/ui/avatar.tsx +53 -0
  37. package/template-nextjs-fullstack/src/components/ui/badge.tsx +42 -0
  38. package/template-nextjs-fullstack/src/components/ui/breadcrumb.tsx +109 -0
  39. package/template-nextjs-fullstack/src/components/ui/button-group.tsx +83 -0
  40. package/template-nextjs-fullstack/src/components/ui/button.tsx +69 -0
  41. package/template-nextjs-fullstack/src/components/ui/calendar.tsx +213 -0
  42. package/template-nextjs-fullstack/src/components/ui/card.tsx +82 -0
  43. package/template-nextjs-fullstack/src/components/ui/carousel.tsx +241 -0
  44. package/template-nextjs-fullstack/src/components/ui/chart.tsx +357 -0
  45. package/template-nextjs-fullstack/src/components/ui/checkbox.tsx +32 -0
  46. package/template-nextjs-fullstack/src/components/ui/collapsible.tsx +33 -0
  47. package/template-nextjs-fullstack/src/components/ui/command.tsx +208 -0
  48. package/template-nextjs-fullstack/src/components/ui/context-menu.tsx +324 -0
  49. package/template-nextjs-fullstack/src/components/ui/dialog.tsx +143 -0
  50. package/template-nextjs-fullstack/src/components/ui/drawer.tsx +135 -0
  51. package/template-nextjs-fullstack/src/components/ui/dropdown-menu.tsx +329 -0
  52. package/template-nextjs-fullstack/src/components/ui/empty.tsx +104 -0
  53. package/template-nextjs-fullstack/src/components/ui/field.tsx +248 -0
  54. package/template-nextjs-fullstack/src/components/ui/form.tsx +167 -0
  55. package/template-nextjs-fullstack/src/components/ui/hover-card.tsx +44 -0
  56. package/template-nextjs-fullstack/src/components/ui/icons/file-ae-colorful-icon.tsx +21 -0
  57. package/template-nextjs-fullstack/src/components/ui/icons/file-ai-colorful-icon.tsx +36 -0
  58. package/template-nextjs-fullstack/src/components/ui/icons/file-android-colorful-icon.tsx +33 -0
  59. package/template-nextjs-fullstack/src/components/ui/icons/file-audio-colorful-icon.tsx +21 -0
  60. package/template-nextjs-fullstack/src/components/ui/icons/file-code-colorful-icon.tsx +28 -0
  61. package/template-nextjs-fullstack/src/components/ui/icons/file-csv-colorful-icon.tsx +21 -0
  62. package/template-nextjs-fullstack/src/components/ui/icons/file-eml-colorful-icon.tsx +29 -0
  63. package/template-nextjs-fullstack/src/components/ui/icons/file-ios-colorful-icon.tsx +25 -0
  64. package/template-nextjs-fullstack/src/components/ui/icons/file-keynote-colorful-icon.tsx +29 -0
  65. package/template-nextjs-fullstack/src/components/ui/icons/file-pages-colorful-icon.tsx +29 -0
  66. package/template-nextjs-fullstack/src/components/ui/icons/file-ps-colorful-icon.tsx +21 -0
  67. package/template-nextjs-fullstack/src/components/ui/icons/file-sketch-colorful-icon.tsx +21 -0
  68. package/template-nextjs-fullstack/src/components/ui/icons/file-slide-colorful-icon.tsx +21 -0
  69. package/template-nextjs-fullstack/src/components/ui/icons/file-vcf-colorful-icon.tsx +29 -0
  70. package/template-nextjs-fullstack/src/components/ui/icons/file-wiki-excel-colorful-icon.tsx +23 -0
  71. package/template-nextjs-fullstack/src/components/ui/icons/file-wiki-image-colorful-icon.tsx +27 -0
  72. package/template-nextjs-fullstack/src/components/ui/icons/file-wiki-pdf-colorful-icon.tsx +20 -0
  73. package/template-nextjs-fullstack/src/components/ui/icons/file-wiki-ppt-colorful-icon.tsx +21 -0
  74. package/template-nextjs-fullstack/src/components/ui/icons/file-wiki-text-colorful-icon.tsx +12 -0
  75. package/template-nextjs-fullstack/src/components/ui/icons/file-wiki-unknown-colorful-icon.tsx +14 -0
  76. package/template-nextjs-fullstack/src/components/ui/icons/file-wiki-video-colorful-icon.tsx +23 -0
  77. package/template-nextjs-fullstack/src/components/ui/icons/file-wiki-word-colorful-icon.tsx +38 -0
  78. package/template-nextjs-fullstack/src/components/ui/icons/file-wiki-zip-colorful-icon.tsx +21 -0
  79. package/template-nextjs-fullstack/src/components/ui/image.tsx +183 -0
  80. package/template-nextjs-fullstack/src/components/ui/input-group.tsx +166 -0
  81. package/template-nextjs-fullstack/src/components/ui/input-otp.tsx +77 -0
  82. package/template-nextjs-fullstack/src/components/ui/input.tsx +21 -0
  83. package/template-nextjs-fullstack/src/components/ui/item.tsx +193 -0
  84. package/template-nextjs-fullstack/src/components/ui/kbd.tsx +28 -0
  85. package/template-nextjs-fullstack/src/components/ui/label.tsx +24 -0
  86. package/template-nextjs-fullstack/src/components/ui/menubar.tsx +348 -0
  87. package/template-nextjs-fullstack/src/components/ui/native-select.tsx +48 -0
  88. package/template-nextjs-fullstack/src/components/ui/navigation-menu.tsx +168 -0
  89. package/template-nextjs-fullstack/src/components/ui/pagination.tsx +127 -0
  90. package/template-nextjs-fullstack/src/components/ui/popover.tsx +48 -0
  91. package/template-nextjs-fullstack/src/components/ui/progress.tsx +31 -0
  92. package/template-nextjs-fullstack/src/components/ui/radio-group.tsx +45 -0
  93. package/template-nextjs-fullstack/src/components/ui/resizable.tsx +56 -0
  94. package/template-nextjs-fullstack/src/components/ui/scroll-area.tsx +58 -0
  95. package/template-nextjs-fullstack/src/components/ui/select.tsx +243 -0
  96. package/template-nextjs-fullstack/src/components/ui/separator.tsx +28 -0
  97. package/template-nextjs-fullstack/src/components/ui/sheet.tsx +139 -0
  98. package/template-nextjs-fullstack/src/components/ui/sidebar.tsx +727 -0
  99. package/template-nextjs-fullstack/src/components/ui/skeleton.tsx +13 -0
  100. package/template-nextjs-fullstack/src/components/ui/slider.tsx +87 -0
  101. package/template-nextjs-fullstack/src/components/ui/sonner.tsx +67 -0
  102. package/template-nextjs-fullstack/src/components/ui/spinner.tsx +16 -0
  103. package/template-nextjs-fullstack/src/components/ui/streamdown.tsx +186 -0
  104. package/template-nextjs-fullstack/src/components/ui/switch.tsx +31 -0
  105. package/template-nextjs-fullstack/src/components/ui/table.tsx +116 -0
  106. package/template-nextjs-fullstack/src/components/ui/tabs.tsx +66 -0
  107. package/template-nextjs-fullstack/src/components/ui/textarea.tsx +18 -0
  108. package/template-nextjs-fullstack/src/components/ui/toggle-group.tsx +83 -0
  109. package/template-nextjs-fullstack/src/components/ui/toggle.tsx +47 -0
  110. package/template-nextjs-fullstack/src/components/ui/tooltip.tsx +61 -0
  111. package/template-nextjs-fullstack/src/db/index.ts +8 -0
  112. package/template-nextjs-fullstack/src/db/schema.ts +11 -0
  113. package/template-nextjs-fullstack/src/hooks/use-mobile.ts +19 -0
  114. package/template-nextjs-fullstack/src/lib/utils.ts +6 -0
  115. package/template-nextjs-fullstack/tailwind.config.ts +10 -0
  116. package/template-nextjs-fullstack/tsconfig.json +34 -0
  117. package/template-nextjs-static/README.md +80 -0
  118. package/template-nextjs-static/_gitignore +41 -0
  119. package/template-nextjs-static/components.json +25 -0
  120. package/template-nextjs-static/eslint.config.js +15 -0
  121. package/template-nextjs-static/next.config.ts +8 -0
  122. package/template-nextjs-static/package.json +77 -0
  123. package/template-nextjs-static/postcss.config.js +8 -0
  124. package/template-nextjs-static/public/favicon.ico +0 -0
  125. package/template-nextjs-static/scripts/build.sh +36 -0
  126. package/template-nextjs-static/src/components/header.tsx +30 -0
  127. package/template-nextjs-static/src/components/theme-provider.tsx +6 -0
  128. package/template-nextjs-static/src/components/ui/README.md +134 -0
  129. package/template-nextjs-static/src/components/ui/accordion.tsx +66 -0
  130. package/template-nextjs-static/src/components/ui/alert-dialog.tsx +157 -0
  131. package/template-nextjs-static/src/components/ui/alert.tsx +71 -0
  132. package/template-nextjs-static/src/components/ui/aspect-ratio.tsx +11 -0
  133. package/template-nextjs-static/src/components/ui/avatar.tsx +53 -0
  134. package/template-nextjs-static/src/components/ui/badge.tsx +42 -0
  135. package/template-nextjs-static/src/components/ui/breadcrumb.tsx +109 -0
  136. package/template-nextjs-static/src/components/ui/button-group.tsx +83 -0
  137. package/template-nextjs-static/src/components/ui/button.tsx +69 -0
  138. package/template-nextjs-static/src/components/ui/calendar.tsx +213 -0
  139. package/template-nextjs-static/src/components/ui/card.tsx +82 -0
  140. package/template-nextjs-static/src/components/ui/carousel.tsx +241 -0
  141. package/template-nextjs-static/src/components/ui/chart.tsx +357 -0
  142. package/template-nextjs-static/src/components/ui/checkbox.tsx +32 -0
  143. package/template-nextjs-static/src/components/ui/collapsible.tsx +33 -0
  144. package/template-nextjs-static/src/components/ui/command.tsx +208 -0
  145. package/template-nextjs-static/src/components/ui/context-menu.tsx +324 -0
  146. package/template-nextjs-static/src/components/ui/dialog.tsx +143 -0
  147. package/template-nextjs-static/src/components/ui/drawer.tsx +135 -0
  148. package/template-nextjs-static/src/components/ui/dropdown-menu.tsx +329 -0
  149. package/template-nextjs-static/src/components/ui/empty.tsx +104 -0
  150. package/template-nextjs-static/src/components/ui/field.tsx +248 -0
  151. package/template-nextjs-static/src/components/ui/form.tsx +167 -0
  152. package/template-nextjs-static/src/components/ui/hover-card.tsx +44 -0
  153. package/template-nextjs-static/src/components/ui/icons/file-ae-colorful-icon.tsx +21 -0
  154. package/template-nextjs-static/src/components/ui/icons/file-ai-colorful-icon.tsx +36 -0
  155. package/template-nextjs-static/src/components/ui/icons/file-android-colorful-icon.tsx +33 -0
  156. package/template-nextjs-static/src/components/ui/icons/file-audio-colorful-icon.tsx +21 -0
  157. package/template-nextjs-static/src/components/ui/icons/file-code-colorful-icon.tsx +28 -0
  158. package/template-nextjs-static/src/components/ui/icons/file-csv-colorful-icon.tsx +21 -0
  159. package/template-nextjs-static/src/components/ui/icons/file-eml-colorful-icon.tsx +29 -0
  160. package/template-nextjs-static/src/components/ui/icons/file-ios-colorful-icon.tsx +25 -0
  161. package/template-nextjs-static/src/components/ui/icons/file-keynote-colorful-icon.tsx +29 -0
  162. package/template-nextjs-static/src/components/ui/icons/file-pages-colorful-icon.tsx +29 -0
  163. package/template-nextjs-static/src/components/ui/icons/file-ps-colorful-icon.tsx +21 -0
  164. package/template-nextjs-static/src/components/ui/icons/file-sketch-colorful-icon.tsx +21 -0
  165. package/template-nextjs-static/src/components/ui/icons/file-slide-colorful-icon.tsx +21 -0
  166. package/template-nextjs-static/src/components/ui/icons/file-vcf-colorful-icon.tsx +29 -0
  167. package/template-nextjs-static/src/components/ui/icons/file-wiki-excel-colorful-icon.tsx +23 -0
  168. package/template-nextjs-static/src/components/ui/icons/file-wiki-image-colorful-icon.tsx +27 -0
  169. package/template-nextjs-static/src/components/ui/icons/file-wiki-pdf-colorful-icon.tsx +20 -0
  170. package/template-nextjs-static/src/components/ui/icons/file-wiki-ppt-colorful-icon.tsx +21 -0
  171. package/template-nextjs-static/src/components/ui/icons/file-wiki-text-colorful-icon.tsx +12 -0
  172. package/template-nextjs-static/src/components/ui/icons/file-wiki-unknown-colorful-icon.tsx +14 -0
  173. package/template-nextjs-static/src/components/ui/icons/file-wiki-video-colorful-icon.tsx +23 -0
  174. package/template-nextjs-static/src/components/ui/icons/file-wiki-word-colorful-icon.tsx +38 -0
  175. package/template-nextjs-static/src/components/ui/icons/file-wiki-zip-colorful-icon.tsx +21 -0
  176. package/template-nextjs-static/src/components/ui/image.tsx +183 -0
  177. package/template-nextjs-static/src/components/ui/input-group.tsx +166 -0
  178. package/template-nextjs-static/src/components/ui/input-otp.tsx +77 -0
  179. package/template-nextjs-static/src/components/ui/input.tsx +21 -0
  180. package/template-nextjs-static/src/components/ui/item.tsx +193 -0
  181. package/template-nextjs-static/src/components/ui/kbd.tsx +28 -0
  182. package/template-nextjs-static/src/components/ui/label.tsx +24 -0
  183. package/template-nextjs-static/src/components/ui/menubar.tsx +348 -0
  184. package/template-nextjs-static/src/components/ui/native-select.tsx +48 -0
  185. package/template-nextjs-static/src/components/ui/navigation-menu.tsx +168 -0
  186. package/template-nextjs-static/src/components/ui/pagination.tsx +127 -0
  187. package/template-nextjs-static/src/components/ui/popover.tsx +48 -0
  188. package/template-nextjs-static/src/components/ui/progress.tsx +31 -0
  189. package/template-nextjs-static/src/components/ui/radio-group.tsx +45 -0
  190. package/template-nextjs-static/src/components/ui/resizable.tsx +56 -0
  191. package/template-nextjs-static/src/components/ui/scroll-area.tsx +58 -0
  192. package/template-nextjs-static/src/components/ui/select.tsx +243 -0
  193. package/template-nextjs-static/src/components/ui/separator.tsx +28 -0
  194. package/template-nextjs-static/src/components/ui/sheet.tsx +139 -0
  195. package/template-nextjs-static/src/components/ui/sidebar.tsx +727 -0
  196. package/template-nextjs-static/src/components/ui/skeleton.tsx +13 -0
  197. package/template-nextjs-static/src/components/ui/slider.tsx +87 -0
  198. package/template-nextjs-static/src/components/ui/sonner.tsx +67 -0
  199. package/template-nextjs-static/src/components/ui/spinner.tsx +16 -0
  200. package/template-nextjs-static/src/components/ui/streamdown.tsx +186 -0
  201. package/template-nextjs-static/src/components/ui/switch.tsx +31 -0
  202. package/template-nextjs-static/src/components/ui/table.tsx +116 -0
  203. package/template-nextjs-static/src/components/ui/tabs.tsx +66 -0
  204. package/template-nextjs-static/src/components/ui/textarea.tsx +18 -0
  205. package/template-nextjs-static/src/components/ui/toggle-group.tsx +83 -0
  206. package/template-nextjs-static/src/components/ui/toggle.tsx +47 -0
  207. package/template-nextjs-static/src/components/ui/tooltip.tsx +61 -0
  208. package/template-nextjs-static/src/hooks/use-mobile.ts +19 -0
  209. package/template-nextjs-static/src/lib/utils.ts +6 -0
  210. package/template-nextjs-static/src/pages/_app.tsx +11 -0
  211. package/template-nextjs-static/src/pages/_document.tsx +13 -0
  212. package/template-nextjs-static/src/pages/hello.tsx +32 -0
  213. package/template-nextjs-static/src/pages/index.tsx +76 -0
  214. package/template-nextjs-static/src/styles/globals.css +143 -0
  215. package/template-nextjs-static/tailwind.config.ts +10 -0
  216. package/template-nextjs-static/tsconfig.json +34 -0
@@ -0,0 +1,47 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as TogglePrimitive from "@radix-ui/react-toggle"
5
+ import { cva, type VariantProps } from "class-variance-authority"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ const toggleVariants = cva(
10
+ "inline-flex items-center justify-center gap-2 rounded-md text-sm font-normal enabled:hover:bg-muted enabled:hover:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/20 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
11
+ {
12
+ variants: {
13
+ variant: {
14
+ default: "bg-transparent",
15
+ outline:
16
+ "border border-input bg-transparent enabled:hover:bg-accent enabled:hover:text-accent-foreground",
17
+ },
18
+ size: {
19
+ default: "h-9 px-2 min-w-9",
20
+ sm: "h-8 px-1.5 min-w-8",
21
+ lg: "h-10 px-2.5 min-w-10",
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ variant: "default",
26
+ size: "default",
27
+ },
28
+ }
29
+ )
30
+
31
+ function Toggle({
32
+ className,
33
+ variant,
34
+ size,
35
+ ...props
36
+ }: React.ComponentProps<typeof TogglePrimitive.Root> &
37
+ VariantProps<typeof toggleVariants>) {
38
+ return (
39
+ <TogglePrimitive.Root
40
+ data-slot="toggle"
41
+ className={cn(toggleVariants({ variant, size, className }))}
42
+ {...props}
43
+ />
44
+ )
45
+ }
46
+
47
+ export { Toggle, toggleVariants }
@@ -0,0 +1,61 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function TooltipProvider({
9
+ delayDuration = 0,
10
+ ...props
11
+ }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
12
+ return (
13
+ <TooltipPrimitive.Provider
14
+ data-slot="tooltip-provider"
15
+ delayDuration={delayDuration}
16
+ {...props}
17
+ />
18
+ )
19
+ }
20
+
21
+ function Tooltip({
22
+ ...props
23
+ }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
24
+ return (
25
+ <TooltipProvider>
26
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
27
+ </TooltipProvider>
28
+ )
29
+ }
30
+
31
+ function TooltipTrigger({
32
+ ...props
33
+ }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
34
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
35
+ }
36
+
37
+ function TooltipContent({
38
+ className,
39
+ sideOffset = 0,
40
+ children,
41
+ ...props
42
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
43
+ return (
44
+ <TooltipPrimitive.Portal>
45
+ <TooltipPrimitive.Content
46
+ data-slot="tooltip-content"
47
+ sideOffset={sideOffset}
48
+ className={cn(
49
+ "bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance shadow-md",
50
+ className
51
+ )}
52
+ {...props}
53
+ >
54
+ {children}
55
+ <TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
56
+ </TooltipPrimitive.Content>
57
+ </TooltipPrimitive.Portal>
58
+ )
59
+ }
60
+
61
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
@@ -0,0 +1,8 @@
1
+ import { drizzle } from "drizzle-orm/postgres-js";
2
+ import postgres from "postgres";
3
+ import * as schema from "./schema";
4
+
5
+ const connectionString = process.env.DATABASE_URL || "";
6
+
7
+ const client = postgres(connectionString);
8
+ export const db = drizzle(client, { schema });
@@ -0,0 +1,11 @@
1
+ import { pgTable, serial, text, boolean, timestamp } from "drizzle-orm/pg-core";
2
+
3
+ export const todos = pgTable("todos", {
4
+ id: serial("id").primaryKey(),
5
+ title: text("title").notNull(),
6
+ completed: boolean("completed").notNull().default(false),
7
+ createdAt: timestamp("created_at").defaultNow().notNull(),
8
+ });
9
+
10
+ export type Todo = typeof todos.$inferSelect;
11
+ export type NewTodo = typeof todos.$inferInsert;
@@ -0,0 +1,19 @@
1
+ import * as React from "react"
2
+
3
+ const MOBILE_BREAKPOINT = 768
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
+
8
+ React.useEffect(() => {
9
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10
+ const onChange = () => {
11
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
12
+ }
13
+ mql.addEventListener("change", onChange)
14
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
15
+ return () => mql.removeEventListener("change", onChange)
16
+ }, [])
17
+
18
+ return !!isMobile
19
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,10 @@
1
+ import type { Config } from 'tailwindcss';
2
+
3
+ const config: Config = {
4
+ content: [
5
+ './src/**/*.{ts,tsx,css}',
6
+ ],
7
+ plugins: [],
8
+ };
9
+
10
+ export default config;
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }
@@ -0,0 +1,80 @@
1
+ # Next.js Pages Router 静态导出模板
2
+
3
+ 纯前端模板,构建产出静态 HTML + JS/CSS,部署到 Nginx + CDN。
4
+
5
+ ## 快速开始
6
+
7
+ ```bash
8
+ npm install
9
+ npm run dev
10
+ ```
11
+
12
+ 打开 http://localhost:3000 查看效果。
13
+
14
+ ## 命令
15
+
16
+ | 命令 | 说明 |
17
+ |---|---|
18
+ | `npm run dev` | 启动开发服务器 |
19
+ | `npm run build` | 构建静态导出到 `out/` |
20
+ | `npm run lint` | 运行 ESLint |
21
+
22
+ ## 构建产出
23
+
24
+ ```bash
25
+ npm run build
26
+ ```
27
+
28
+ 产出 `out/` 目录:
29
+
30
+ ```
31
+ out/
32
+ ├── index.html # 首页
33
+ ├── hello.html # /hello 路由
34
+ ├── 404.html # 404 页面
35
+ └── _next/static/ # JS、CSS、字体 → 部署到 CDN
36
+ ```
37
+
38
+ - 每个路由一个 HTML 文件(构建时预渲染,天然 SEO 友好)
39
+ - 无 RSC payload(.txt 文件),产物干净
40
+ - `_next/static/` 通过 `assetPrefix` 指向 CDN
41
+
42
+ ## 部署
43
+
44
+ ```
45
+ HTML 文件 → Nginx / 静态服务器
46
+ _next/static/ → CDN(通过 assetPrefix 配置)
47
+ ```
48
+
49
+ 配置 CDN 地址:
50
+
51
+ ```ts
52
+ // next.config.ts
53
+ const nextConfig = {
54
+ output: "export",
55
+ assetPrefix: "https://cdn.example.com",
56
+ };
57
+ ```
58
+
59
+ ## 技术栈
60
+
61
+ - Next.js 16(Pages Router、Static Export)
62
+ - React 19、TypeScript 5
63
+ - Tailwind CSS 4 + shadcn/ui(new-york 风格、lucide 图标)
64
+ - next-themes(暗色模式)
65
+ - framer-motion(动画)
66
+
67
+ ## 添加新页面
68
+
69
+ 在 `src/pages/` 下创建文件即可,文件名即路由:
70
+
71
+ ```
72
+ src/pages/about.tsx → /about
73
+ src/pages/blog.tsx → /blog
74
+ ```
75
+
76
+ ## 添加 shadcn/ui 组件
77
+
78
+ ```bash
79
+ npx shadcn@latest add <component-name>
80
+ ```
@@ -0,0 +1,41 @@
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
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "base-nova",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "tailwind.config.ts",
8
+ "css": "src/styles/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
+ }
@@ -0,0 +1,15 @@
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
+ );
@@ -0,0 +1,8 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ output: "export",
5
+ // assetPrefix: 'https://cdn.example.com', // uncomment for CDN
6
+ };
7
+
8
+ export default nextConfig;
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "mclaw": {
6
+ "stack": "nextjs-static",
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
+ },
15
+ "dependencies": {
16
+ "@base-ui/react": "^1.3.0",
17
+ "@radix-ui/react-accordion": "^1.2.12",
18
+ "@radix-ui/react-alert-dialog": "^1.1.15",
19
+ "@radix-ui/react-aspect-ratio": "^1.1.7",
20
+ "@radix-ui/react-avatar": "^1.1.10",
21
+ "@radix-ui/react-checkbox": "^1.3.3",
22
+ "@radix-ui/react-collapsible": "^1.1.12",
23
+ "@radix-ui/react-context-menu": "^2.2.16",
24
+ "@radix-ui/react-dialog": "^1.1.15",
25
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
26
+ "@radix-ui/react-hover-card": "^1.1.15",
27
+ "@radix-ui/react-label": "^2.1.7",
28
+ "@radix-ui/react-menubar": "^1.1.16",
29
+ "@radix-ui/react-navigation-menu": "^1.2.14",
30
+ "@radix-ui/react-popover": "^1.1.15",
31
+ "@radix-ui/react-progress": "^1.1.7",
32
+ "@radix-ui/react-radio-group": "^1.3.8",
33
+ "@radix-ui/react-scroll-area": "^1.2.10",
34
+ "@radix-ui/react-select": "^2.2.6",
35
+ "@radix-ui/react-separator": "^1.1.7",
36
+ "@radix-ui/react-slider": "^1.3.6",
37
+ "@radix-ui/react-slot": "^1.2.3",
38
+ "@radix-ui/react-switch": "^1.2.6",
39
+ "@radix-ui/react-tabs": "^1.1.13",
40
+ "@radix-ui/react-toggle": "^1.1.10",
41
+ "@radix-ui/react-toggle-group": "^1.1.11",
42
+ "@radix-ui/react-tooltip": "^1.2.8",
43
+ "class-variance-authority": "^0.7.1",
44
+ "clsx": "^2.1.1",
45
+ "cmdk": "^1.1.1",
46
+ "embla-carousel-react": "^8.6.0",
47
+ "es-toolkit": "^1.43.0",
48
+ "framer-motion": "^12.36.0",
49
+ "input-otp": "^1.4.2",
50
+ "lucide-react": "^0.577.0",
51
+ "next": "16.1.6",
52
+ "next-themes": "^0.4.6",
53
+ "react": "19.2.3",
54
+ "react-day-picker": "^9.11.1",
55
+ "react-dom": "19.2.3",
56
+ "react-hook-form": "^7.65.0",
57
+ "react-resizable-panels": "^3.0.6",
58
+ "recharts": "^2.15.4",
59
+ "shadcn": "^4.0.8",
60
+ "sonner": "^2.0.7",
61
+ "streamdown": "^1.6.10",
62
+ "tailwind-merge": "^3.5.0",
63
+ "tw-animate-css": "^1.4.0",
64
+ "vaul": "^1.1.2"
65
+ },
66
+ "devDependencies": {
67
+ "@eslint/js": "^9",
68
+ "@tailwindcss/postcss": "^4",
69
+ "@types/node": "^20",
70
+ "@types/react": "^19",
71
+ "@types/react-dom": "^19",
72
+ "eslint": "^9",
73
+ "tailwindcss": "^4",
74
+ "typescript": "^5",
75
+ "typescript-eslint": "^8"
76
+ }
77
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @type {import('postcss-load-config').Config}
3
+ */
4
+ module.exports = {
5
+ plugins: {
6
+ '@tailwindcss/postcss': {},
7
+ },
8
+ };
@@ -0,0 +1,36 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
5
+ OUTPUT="$ROOT/dist/output"
6
+ OUTPUT_STATIC="$ROOT/dist/output_static"
7
+ OUTPUT_RESOURCE="$ROOT/dist/output_resource"
8
+
9
+ # 清理
10
+ rm -rf "$ROOT/dist"
11
+
12
+ # 1. Next.js 构建 → out/
13
+ npx next build
14
+
15
+ # 2. HTML → dist/output/
16
+ mkdir -p "$OUTPUT"
17
+ find "$ROOT/out" -maxdepth 1 -name '*.html' -exec cp {} "$OUTPUT/" \;
18
+ # 复制子目录(排除 _next)
19
+ find "$ROOT/out" -mindepth 1 -maxdepth 1 -type d -not -name '_next' \
20
+ -exec cp -r {} "$OUTPUT/" \;
21
+
22
+ # 生成 routes.json
23
+ echo '{ "version": 1, "type": "nextjs-static", "fallback": "404.html" }' > "$OUTPUT/routes.json"
24
+
25
+ # 3. _next/static/ → dist/output_resource/(JS/CSS/字体,上传到 CDN)
26
+ if [ -d "$ROOT/out/_next/static" ]; then
27
+ mkdir -p "$OUTPUT_RESOURCE/_next"
28
+ cp -r "$ROOT/out/_next/static" "$OUTPUT_RESOURCE/_next/"
29
+ fi
30
+
31
+ # 4. 私有资源 → dist/output_static/(如有,按需补充)
32
+
33
+ echo "Build complete"
34
+ echo " HTML → dist/output/"
35
+ [ -d "$OUTPUT_RESOURCE" ] && echo " Resource → dist/output_resource/"
36
+ [ -d "$OUTPUT_STATIC" ] && echo " Static → dist/output_static/"
@@ -0,0 +1,30 @@
1
+ import { Moon, Sun } from "lucide-react";
2
+ import { useTheme } from "next-themes";
3
+ import { Button } from "@/components/ui/button";
4
+ import Link from "next/link";
5
+
6
+ export function Header() {
7
+ const { theme, setTheme } = useTheme();
8
+
9
+ return (
10
+ <header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
11
+ <div className="container flex h-14 items-center justify-between mx-auto px-4">
12
+ <div className="flex items-center gap-6">
13
+ <Link href="/" className="font-semibold">OpenClaw</Link>
14
+ <nav className="flex items-center gap-4 text-sm">
15
+ <Link href="/hello" className="text-muted-foreground hover:text-foreground transition-colors">Hello</Link>
16
+ </nav>
17
+ </div>
18
+ <Button
19
+ variant="ghost"
20
+ size="icon"
21
+ onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
22
+ >
23
+ <Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
24
+ <Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
25
+ <span className="sr-only">切换主题</span>
26
+ </Button>
27
+ </div>
28
+ </header>
29
+ );
30
+ }
@@ -0,0 +1,6 @@
1
+ import * as React from "react";
2
+ import { ThemeProvider as NextThemesProvider } from "next-themes";
3
+
4
+ export function ThemeProvider({ children, ...props }: React.ComponentProps<typeof NextThemesProvider>) {
5
+ return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
6
+ }
@@ -0,0 +1,134 @@
1
+ # shadcn/ui 组件开发指南
2
+
3
+ ## 核心原则
4
+
5
+ - 组件位置:`/client/src/components/ui/`
6
+ - 图标库:必须使用 `lucide-react`,禁用 Emoji
7
+ - 查阅源码实现:直接读取组件源码了解最新组件实现
8
+ - 交互系统:Button、Badge 使用 elevate 遮罩系统处理 hover/active 状态(通过 `::after` 伪元素叠加 `--elevate-1` / `--elevate-2`)
9
+
10
+ ## 关键组件规范
11
+
12
+ #### 1. Button 组件
13
+
14
+ **导入路径**:`import { Button } from '@/components/ui/button'`
15
+
16
+ **Props**:
17
+ - `variant`: `"link" | "default" | "destructive" | "outline" | "secondary" | "ghost"` - 按钮样式变体
18
+
19
+ ```tsx
20
+ // ✅ 使用变体
21
+ <Button variant="secondary">标准按钮</Button>
22
+
23
+ // ✅ 自定义颜色时必须配对前景色
24
+ <Button className="bg-primary text-primary-foreground">自定义按钮</Button>
25
+ ```
26
+
27
+ #### 2. Badge 组件
28
+
29
+ **导入路径**:`import { Badge } from '@/components/ui/badge'`
30
+
31
+ **Props**:
32
+ - `variant`: `"default" | "destructive" | "outline" | "secondary"` - 样式变体
33
+
34
+ ```tsx
35
+ // ✅ 使用变体
36
+ <Badge>默认</Badge>
37
+ <Badge variant="secondary">次要</Badge>
38
+ <Badge variant="outline">边框</Badge>
39
+ <Badge variant="destructive">危险</Badge>
40
+ ```
41
+
42
+ #### 3. Alert 组件
43
+
44
+ **导入路径**:`import { Alert, AlertTitle, AlertDescription, AlertAction } from '@/components/ui/alert'`
45
+
46
+ **Props**:
47
+ - `variant`: `"default" | "destructive" | "success" | "warning"` - 样式变体
48
+
49
+ ```tsx
50
+ // ✅ default / destructive / success / warning 四种变体
51
+ <Alert variant="success">
52
+ <CheckCircle className="size-4" />
53
+ <AlertTitle>操作成功</AlertTitle>
54
+ <AlertDescription>您的更改已保存</AlertDescription>
55
+ </Alert>
56
+
57
+ <Alert variant="warning">
58
+ <AlertTriangle className="size-4" />
59
+ <AlertTitle>警告</AlertTitle>
60
+ <AlertDescription>请注意检查</AlertDescription>
61
+ </Alert>
62
+
63
+ ```
64
+
65
+ #### 4. Empty 组件
66
+
67
+ **导入路径**:`import { Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent } from '@/components/ui/empty'`
68
+
69
+ **子组件 Props**:
70
+ - `EmptyMedia` 组件的 `variant`: `"default" | "icon"` - 媒体展示方式
71
+
72
+ ```tsx
73
+ // 标准结构:EmptyHeader 包含 EmptyMedia + EmptyTitle + EmptyDescription
74
+ <Empty>
75
+ <EmptyHeader>
76
+ <EmptyMedia variant="icon">
77
+ <SearchIcon className="size-6" />
78
+ </EmptyMedia>
79
+ <EmptyTitle>暂无数据</EmptyTitle>
80
+ <EmptyDescription>当前没有找到相关内容</EmptyDescription>
81
+ </EmptyHeader>
82
+ <EmptyContent>
83
+ <Button>添加数据</Button>
84
+ </EmptyContent>
85
+ </Empty>
86
+ ```
87
+
88
+ #### 5. Card Padding 系统
89
+
90
+ **导入路径**:`import { CardHeader, CardContent, CardFooter } from '@/components/ui/card'`
91
+
92
+ - `CardHeader`: `p-6` (24px 全方向)
93
+ - `CardContent`: `p-6 pt-0` (与 header 无缝衔接)
94
+ - `CardFooter`: `p-6 pt-0` (与 content 无缝衔接)
95
+
96
+ #### 6. Dialog 组件
97
+
98
+ **导入路径**:`import { Dialog, DialogContent } from '@/components/ui/dialog'`
99
+
100
+ Dialog 默认提供了右上角的close能力,同时也提供了自定义关闭按钮的能力,即通过设置showCloseButton为false来关闭默认的关闭按钮。所以当默认存在close时,禁止在内容区域提供自定义的关闭按钮。
101
+
102
+ #### 7. Image 组件
103
+
104
+ **导入路径**:`import { Image } from '@/components/ui/image'`
105
+
106
+ **Props**:支持原生 `<img>` 标签所有属性。
107
+
108
+ ```typescript
109
+ interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement>
110
+ ```
111
+
112
+ **使用规范**:
113
+
114
+ 1. **响应式图片场景**:当图片尺寸需要根据视口宽度变化时,必须设置 `sizes` 属性
115
+ 2. **固定尺寸图片场景**:当图片有固定尺寸时,必须设置 `width` 属性(number 类型)
116
+ 3. **必须提供有意义的 `alt` 属性**
117
+
118
+ ```tsx
119
+ // ✅ 响应式图片
120
+ <Image
121
+ src="/path/to/image.jpg"
122
+ alt="描述文字"
123
+ sizes="(max-width: 768px) 100vw, 50vw"
124
+ />
125
+
126
+ // ✅ 固定尺寸图片(width/height 使用 number)
127
+ <Image
128
+ src="/path/to/image.jpg"
129
+ alt="描述文字"
130
+ width={300}
131
+ height={200}
132
+ />
133
+
134
+ ```