create-next-imagicma 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +42 -0
  2. package/bin/create-next-imagicma.mjs +220 -0
  3. package/package.json +19 -0
  4. package/template/.env.example +10 -0
  5. package/template/AGENTS.md +146 -0
  6. package/template/README.md +36 -0
  7. package/template/app/_components/DevPreviewShield.tsx +638 -0
  8. package/template/app/api/greeting/route.ts +27 -0
  9. package/template/app/error.tsx +93 -0
  10. package/template/app/favicon.ico +0 -0
  11. package/template/app/globals.css +145 -0
  12. package/template/app/hello/_components/HelloClient.tsx +94 -0
  13. package/template/app/hello/page.tsx +23 -0
  14. package/template/app/layout.tsx +29 -0
  15. package/template/app/page.tsx +49 -0
  16. package/template/app/providers.tsx +25 -0
  17. package/template/components/ui/accordion.tsx +58 -0
  18. package/template/components/ui/alert-dialog.tsx +141 -0
  19. package/template/components/ui/alert.tsx +61 -0
  20. package/template/components/ui/aspect-ratio.tsx +7 -0
  21. package/template/components/ui/avatar.tsx +51 -0
  22. package/template/components/ui/badge.tsx +40 -0
  23. package/template/components/ui/breadcrumb.tsx +117 -0
  24. package/template/components/ui/button.tsx +64 -0
  25. package/template/components/ui/calendar.tsx +72 -0
  26. package/template/components/ui/card.tsx +87 -0
  27. package/template/components/ui/carousel.tsx +262 -0
  28. package/template/components/ui/chart.tsx +365 -0
  29. package/template/components/ui/checkbox.tsx +30 -0
  30. package/template/components/ui/collapsible.tsx +11 -0
  31. package/template/components/ui/command.tsx +153 -0
  32. package/template/components/ui/context-menu.tsx +200 -0
  33. package/template/components/ui/dialog.tsx +122 -0
  34. package/template/components/ui/drawer.tsx +118 -0
  35. package/template/components/ui/dropdown-menu.tsx +200 -0
  36. package/template/components/ui/form.tsx +178 -0
  37. package/template/components/ui/hover-card.tsx +29 -0
  38. package/template/components/ui/input-otp.tsx +71 -0
  39. package/template/components/ui/input.tsx +25 -0
  40. package/template/components/ui/label.tsx +26 -0
  41. package/template/components/ui/menubar.tsx +256 -0
  42. package/template/components/ui/navigation-menu.tsx +130 -0
  43. package/template/components/ui/pagination.tsx +119 -0
  44. package/template/components/ui/popover.tsx +31 -0
  45. package/template/components/ui/progress.tsx +28 -0
  46. package/template/components/ui/radio-group.tsx +44 -0
  47. package/template/components/ui/resizable.tsx +45 -0
  48. package/template/components/ui/scroll-area.tsx +48 -0
  49. package/template/components/ui/select.tsx +160 -0
  50. package/template/components/ui/separator.tsx +31 -0
  51. package/template/components/ui/sheet.tsx +140 -0
  52. package/template/components/ui/sidebar.tsx +732 -0
  53. package/template/components/ui/skeleton.tsx +17 -0
  54. package/template/components/ui/slider.tsx +28 -0
  55. package/template/components/ui/switch.tsx +29 -0
  56. package/template/components/ui/table.tsx +119 -0
  57. package/template/components/ui/tabs.tsx +55 -0
  58. package/template/components/ui/textarea.tsx +24 -0
  59. package/template/components/ui/toast.tsx +129 -0
  60. package/template/components/ui/toaster.tsx +35 -0
  61. package/template/components/ui/toggle-group.tsx +61 -0
  62. package/template/components/ui/toggle.tsx +45 -0
  63. package/template/components/ui/tooltip.tsx +30 -0
  64. package/template/drizzle.config.ts +50 -0
  65. package/template/eslint.config.mjs +18 -0
  66. package/template/hooks/use-greeting.ts +15 -0
  67. package/template/hooks/use-mobile.ts +21 -0
  68. package/template/hooks/use-toast.ts +194 -0
  69. package/template/lib/queryClient.ts +59 -0
  70. package/template/lib/utils.ts +6 -0
  71. package/template/next.config.ts +8 -0
  72. package/template/package.json +81 -0
  73. package/template/pnpm-lock.yaml +6937 -0
  74. package/template/postcss.config.mjs +7 -0
  75. package/template/public/file.svg +1 -0
  76. package/template/public/globe.svg +1 -0
  77. package/template/public/next.svg +1 -0
  78. package/template/public/vercel.svg +1 -0
  79. package/template/public/window.svg +1 -0
  80. package/template/server/db.ts +24 -0
  81. package/template/server/storage.ts +41 -0
  82. package/template/shared/routes.ts +13 -0
  83. package/template/shared/schema.ts +17 -0
  84. package/template/tailwind.config.mjs +96 -0
  85. package/template/tsconfig.json +35 -0
  86. package/template/types/pg.d.ts +19 -0
@@ -0,0 +1,194 @@
1
+ "use client";
2
+
3
+ import * as React from "react"
4
+
5
+ import type {
6
+ ToastActionElement,
7
+ ToastProps,
8
+ } from "@/components/ui/toast"
9
+
10
+ const TOAST_LIMIT = 1
11
+ const TOAST_REMOVE_DELAY = 1000000
12
+
13
+ type ToasterToast = ToastProps & {
14
+ id: string
15
+ title?: React.ReactNode
16
+ description?: React.ReactNode
17
+ action?: ToastActionElement
18
+ }
19
+
20
+ const actionTypes = {
21
+ ADD_TOAST: "ADD_TOAST",
22
+ UPDATE_TOAST: "UPDATE_TOAST",
23
+ DISMISS_TOAST: "DISMISS_TOAST",
24
+ REMOVE_TOAST: "REMOVE_TOAST",
25
+ } as const
26
+
27
+ let count = 0
28
+
29
+ function genId() {
30
+ count = (count + 1) % Number.MAX_SAFE_INTEGER
31
+ return count.toString()
32
+ }
33
+
34
+ type ActionType = typeof actionTypes
35
+
36
+ type Action =
37
+ | {
38
+ type: ActionType["ADD_TOAST"]
39
+ toast: ToasterToast
40
+ }
41
+ | {
42
+ type: ActionType["UPDATE_TOAST"]
43
+ toast: Partial<ToasterToast>
44
+ }
45
+ | {
46
+ type: ActionType["DISMISS_TOAST"]
47
+ toastId?: ToasterToast["id"]
48
+ }
49
+ | {
50
+ type: ActionType["REMOVE_TOAST"]
51
+ toastId?: ToasterToast["id"]
52
+ }
53
+
54
+ interface State {
55
+ toasts: ToasterToast[]
56
+ }
57
+
58
+ const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
59
+
60
+ const addToRemoveQueue = (toastId: string) => {
61
+ if (toastTimeouts.has(toastId)) {
62
+ return
63
+ }
64
+
65
+ const timeout = setTimeout(() => {
66
+ toastTimeouts.delete(toastId)
67
+ dispatch({
68
+ type: actionTypes.REMOVE_TOAST,
69
+ toastId: toastId,
70
+ })
71
+ }, TOAST_REMOVE_DELAY)
72
+
73
+ toastTimeouts.set(toastId, timeout)
74
+ }
75
+
76
+ export const reducer = (state: State, action: Action): State => {
77
+ switch (action.type) {
78
+ case actionTypes.ADD_TOAST:
79
+ return {
80
+ ...state,
81
+ toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
82
+ }
83
+
84
+ case actionTypes.UPDATE_TOAST:
85
+ return {
86
+ ...state,
87
+ toasts: state.toasts.map((t) =>
88
+ t.id === action.toast.id ? { ...t, ...action.toast } : t
89
+ ),
90
+ }
91
+
92
+ case actionTypes.DISMISS_TOAST: {
93
+ const { toastId } = action
94
+
95
+ // ! Side effects ! - This could be extracted into a dismissToast() action,
96
+ // but I'll keep it here for simplicity
97
+ if (toastId) {
98
+ addToRemoveQueue(toastId)
99
+ } else {
100
+ state.toasts.forEach((toast) => {
101
+ addToRemoveQueue(toast.id)
102
+ })
103
+ }
104
+
105
+ return {
106
+ ...state,
107
+ toasts: state.toasts.map((t) =>
108
+ t.id === toastId || toastId === undefined
109
+ ? {
110
+ ...t,
111
+ open: false,
112
+ }
113
+ : t
114
+ ),
115
+ }
116
+ }
117
+ case actionTypes.REMOVE_TOAST:
118
+ if (action.toastId === undefined) {
119
+ return {
120
+ ...state,
121
+ toasts: [],
122
+ }
123
+ }
124
+ return {
125
+ ...state,
126
+ toasts: state.toasts.filter((t) => t.id !== action.toastId),
127
+ }
128
+ }
129
+ }
130
+
131
+ const listeners: Array<(state: State) => void> = []
132
+
133
+ let memoryState: State = { toasts: [] }
134
+
135
+ function dispatch(action: Action) {
136
+ memoryState = reducer(memoryState, action)
137
+ listeners.forEach((listener) => {
138
+ listener(memoryState)
139
+ })
140
+ }
141
+
142
+ type Toast = Omit<ToasterToast, "id">
143
+
144
+ function toast({ ...props }: Toast) {
145
+ const id = genId()
146
+
147
+ const update = (props: ToasterToast) =>
148
+ dispatch({
149
+ type: actionTypes.UPDATE_TOAST,
150
+ toast: { ...props, id },
151
+ })
152
+ const dismiss = () => dispatch({ type: actionTypes.DISMISS_TOAST, toastId: id })
153
+
154
+ dispatch({
155
+ type: actionTypes.ADD_TOAST,
156
+ toast: {
157
+ ...props,
158
+ id,
159
+ open: true,
160
+ onOpenChange: (open) => {
161
+ if (!open) dismiss()
162
+ },
163
+ },
164
+ })
165
+
166
+ return {
167
+ id: id,
168
+ dismiss,
169
+ update,
170
+ }
171
+ }
172
+
173
+ function useToast() {
174
+ const [state, setState] = React.useState<State>(memoryState)
175
+
176
+ React.useEffect(() => {
177
+ listeners.push(setState)
178
+ return () => {
179
+ const index = listeners.indexOf(setState)
180
+ if (index > -1) {
181
+ listeners.splice(index, 1)
182
+ }
183
+ }
184
+ }, [state])
185
+
186
+ return {
187
+ ...state,
188
+ toast,
189
+ dismiss: (toastId?: string) =>
190
+ dispatch({ type: actionTypes.DISMISS_TOAST, toastId }),
191
+ }
192
+ }
193
+
194
+ export { useToast, toast }
@@ -0,0 +1,59 @@
1
+ import { QueryClient, QueryFunction } from "@tanstack/react-query";
2
+
3
+ async function throwIfResNotOk(res: Response) {
4
+ if (!res.ok) {
5
+ const text = (await res.text()) || res.statusText;
6
+ throw new Error(`${res.status}: ${text}`);
7
+ }
8
+ }
9
+
10
+ export async function apiRequest(
11
+ method: string,
12
+ url: string,
13
+ data?: unknown | undefined,
14
+ ): Promise<Response> {
15
+ const res = await fetch(url, {
16
+ method,
17
+ headers: data ? { "Content-Type": "application/json" } : {},
18
+ body: data ? JSON.stringify(data) : undefined,
19
+ credentials: "include",
20
+ });
21
+
22
+ await throwIfResNotOk(res);
23
+ return res;
24
+ }
25
+
26
+ type UnauthorizedBehavior = "returnNull" | "throw";
27
+ export const getQueryFn: <T>(options: {
28
+ on401: UnauthorizedBehavior;
29
+ }) => QueryFunction<T> =
30
+ ({ on401: unauthorizedBehavior }) =>
31
+ async ({ queryKey }) => {
32
+ const res = await fetch(queryKey.join("/") as string, {
33
+ credentials: "include",
34
+ });
35
+
36
+ if (unauthorizedBehavior === "returnNull" && res.status === 401) {
37
+ return null;
38
+ }
39
+
40
+ await throwIfResNotOk(res);
41
+ return await res.json();
42
+ };
43
+
44
+ export function makeQueryClient() {
45
+ return new QueryClient({
46
+ defaultOptions: {
47
+ queries: {
48
+ queryFn: getQueryFn({ on401: "throw" }),
49
+ refetchInterval: false,
50
+ refetchOnWindowFocus: false,
51
+ staleTime: Infinity,
52
+ retry: false,
53
+ },
54
+ mutations: {
55
+ retry: false,
56
+ },
57
+ },
58
+ });
59
+ }
@@ -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,8 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ // 默认隐藏 Next.js 开发态的右下角/角落指示器(例如 “Compiling…”)
5
+ devIndicators: false,
6
+ };
7
+
8
+ export default nextConfig;
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "nextjs-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "packageManager": "pnpm@9",
6
+ "engines": {
7
+ "packageManager": "pnpm@>=9"
8
+ },
9
+ "scripts": {
10
+ "preinstall": "npx only-allow pnpm",
11
+ "dev": "next dev",
12
+ "build": "next build --webpack",
13
+ "start": "next start",
14
+ "check": "tsc -p tsconfig.json --noEmit",
15
+ "db:push": "drizzle-kit push",
16
+ "lint": "eslint"
17
+ },
18
+ "dependencies": {
19
+ "@radix-ui/react-accordion": "^1.2.4",
20
+ "@radix-ui/react-alert-dialog": "^1.1.7",
21
+ "@radix-ui/react-aspect-ratio": "^1.1.3",
22
+ "@radix-ui/react-avatar": "^1.1.4",
23
+ "@radix-ui/react-checkbox": "^1.1.5",
24
+ "@radix-ui/react-collapsible": "^1.1.4",
25
+ "@radix-ui/react-context-menu": "^2.2.7",
26
+ "@radix-ui/react-dialog": "^1.1.7",
27
+ "@radix-ui/react-dropdown-menu": "^2.1.7",
28
+ "@radix-ui/react-hover-card": "^1.1.7",
29
+ "@radix-ui/react-label": "^2.1.3",
30
+ "@radix-ui/react-menubar": "^1.1.7",
31
+ "@radix-ui/react-navigation-menu": "^1.2.6",
32
+ "@radix-ui/react-popover": "^1.1.7",
33
+ "@radix-ui/react-progress": "^1.1.3",
34
+ "@radix-ui/react-radio-group": "^1.2.4",
35
+ "@radix-ui/react-scroll-area": "^1.2.4",
36
+ "@radix-ui/react-select": "^2.1.7",
37
+ "@radix-ui/react-separator": "^1.1.3",
38
+ "@radix-ui/react-slider": "^1.2.4",
39
+ "@radix-ui/react-slot": "^1.2.0",
40
+ "@radix-ui/react-switch": "^1.1.4",
41
+ "@radix-ui/react-tabs": "^1.1.4",
42
+ "@radix-ui/react-toast": "^1.2.7",
43
+ "@radix-ui/react-toggle": "^1.1.3",
44
+ "@radix-ui/react-toggle-group": "^1.1.3",
45
+ "@radix-ui/react-tooltip": "^1.2.0",
46
+ "@tanstack/react-query": "^5.60.5",
47
+ "class-variance-authority": "^0.7.1",
48
+ "clsx": "^2.1.1",
49
+ "cmdk": "^1.1.1",
50
+ "drizzle-orm": "^0.39.3",
51
+ "drizzle-zod": "^0.7.0",
52
+ "embla-carousel-react": "^8.6.0",
53
+ "framer-motion": "^11.18.2",
54
+ "input-otp": "^1.4.2",
55
+ "lucide-react": "^0.453.0",
56
+ "next": "16.1.6",
57
+ "next-themes": "^0.4.6",
58
+ "pg": "^8.16.3",
59
+ "react": "19.2.3",
60
+ "react-day-picker": "^9.13.0",
61
+ "react-dom": "19.2.3",
62
+ "react-hook-form": "^7.55.0",
63
+ "react-resizable-panels": "^2.1.7",
64
+ "recharts": "^2.15.2",
65
+ "tailwind-merge": "^2.6.0",
66
+ "vaul": "^1.1.2",
67
+ "zod": "^3.24.2"
68
+ },
69
+ "devDependencies": {
70
+ "@tailwindcss/postcss": "^4",
71
+ "@types/node": "^20",
72
+ "@types/react": "^19",
73
+ "@types/react-dom": "^19",
74
+ "drizzle-kit": "^0.31.8",
75
+ "eslint": "^9",
76
+ "eslint-config-next": "16.1.6",
77
+ "tailwindcss": "^4",
78
+ "tailwindcss-animate": "^1.0.7",
79
+ "typescript": "^5"
80
+ }
81
+ }