create-next-imagicma 0.0.1 → 0.0.3
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/README.md +2 -1
- package/bin/create-next-imagicma.mjs +130 -11
- package/package.json +1 -1
- package/template/AGENTS.md +80 -1
- package/template/README.md +0 -2
- package/template/app/_components/DevPreviewShield.tsx +6 -6
- package/template/app/globals.css +291 -0
- package/template/app/layout.tsx +6 -1
- package/template/lib/theme/default-theme.ts +11 -0
- package/template/package.json +1 -6
- package/template/process-compose.yaml +13 -0
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install -g create-next-imagicma
|
|
9
|
-
create-next-imagicma <project-dir> [--port <1-65535>]
|
|
9
|
+
create-next-imagicma <project-dir> [--port <1-65535>] [--theme <name>]
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
本地(未发布)使用示例:
|
|
@@ -19,6 +19,7 @@ node ./create-next-imagicma/bin/create-next-imagicma.mjs demo-5001 --port 5001
|
|
|
19
19
|
## 参数
|
|
20
20
|
|
|
21
21
|
- `--port <number>`:设置新项目 `dev/start` 的默认端口(写入 `next ... -p <port>`)。
|
|
22
|
+
- `--theme <name>`:设置新项目默认主题(可选:`quadratic`、`nomad`、`honey`、`zen-garden`、`highlighter`)。
|
|
22
23
|
- 运行时仍可覆盖,例如:`pnpm dev -- -p 6001` 或 `PORT=6001 pnpm start`
|
|
23
24
|
|
|
24
25
|
## 依赖安装策略
|
|
@@ -8,12 +8,20 @@ import { fileURLToPath } from "node:url";
|
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = path.dirname(__filename);
|
|
10
10
|
const TEMPLATE_DIR = path.resolve(__dirname, "..", "template");
|
|
11
|
+
const THEME_STYLES = [
|
|
12
|
+
"quadratic",
|
|
13
|
+
"nomad",
|
|
14
|
+
"honey",
|
|
15
|
+
"zen-garden",
|
|
16
|
+
"highlighter",
|
|
17
|
+
];
|
|
11
18
|
|
|
12
19
|
function printHelp() {
|
|
13
|
-
console.log(`create-next-imagicma <project-dir> [--port <1-65535>]
|
|
20
|
+
console.log(`create-next-imagicma <project-dir> [--port <1-65535>] [--theme <name>]
|
|
14
21
|
|
|
15
22
|
参数:
|
|
16
23
|
--port <number> 设置新项目 dev/start 的默认端口(next ... -p)
|
|
24
|
+
--theme <name> 设置默认主题(可选:${THEME_STYLES.join(", ")})
|
|
17
25
|
-h, --help 显示帮助
|
|
18
26
|
`);
|
|
19
27
|
}
|
|
@@ -28,6 +36,25 @@ function parsePort(raw) {
|
|
|
28
36
|
return port;
|
|
29
37
|
}
|
|
30
38
|
|
|
39
|
+
function parseTheme(raw) {
|
|
40
|
+
const normalized = String(raw ?? "")
|
|
41
|
+
.trim()
|
|
42
|
+
.toLowerCase()
|
|
43
|
+
.replace(/[_\s]+/gu, "-");
|
|
44
|
+
|
|
45
|
+
if (!normalized) {
|
|
46
|
+
throw new Error("--theme 缺少值:请使用 --theme <name>");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!THEME_STYLES.includes(normalized)) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`--theme 参数不合法:${JSON.stringify(raw)}(可选:${THEME_STYLES.join(", ")})`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return normalized;
|
|
56
|
+
}
|
|
57
|
+
|
|
31
58
|
function sanitizePackageName(raw) {
|
|
32
59
|
const normalized = raw
|
|
33
60
|
.toLowerCase()
|
|
@@ -39,6 +66,7 @@ function sanitizePackageName(raw) {
|
|
|
39
66
|
function parseArgs(argv) {
|
|
40
67
|
let projectDir;
|
|
41
68
|
let port;
|
|
69
|
+
let theme;
|
|
42
70
|
|
|
43
71
|
for (let i = 0; i < argv.length; i += 1) {
|
|
44
72
|
const arg = argv[i];
|
|
@@ -62,6 +90,21 @@ function parseArgs(argv) {
|
|
|
62
90
|
continue;
|
|
63
91
|
}
|
|
64
92
|
|
|
93
|
+
if (arg === "--theme") {
|
|
94
|
+
const value = argv[i + 1];
|
|
95
|
+
if (!value) {
|
|
96
|
+
throw new Error("--theme 缺少值:请使用 --theme <name>");
|
|
97
|
+
}
|
|
98
|
+
theme = parseTheme(value);
|
|
99
|
+
i += 1;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (arg.startsWith("--theme=")) {
|
|
104
|
+
theme = parseTheme(arg.slice("--theme=".length));
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
65
108
|
if (arg.startsWith("-")) {
|
|
66
109
|
throw new Error(`未知参数:${arg}`);
|
|
67
110
|
}
|
|
@@ -78,21 +121,18 @@ function parseArgs(argv) {
|
|
|
78
121
|
throw new Error("缺少 <project-dir>:请指定要创建的项目目录名/路径");
|
|
79
122
|
}
|
|
80
123
|
|
|
81
|
-
return { projectDir, port, help: false };
|
|
124
|
+
return { projectDir, port, theme, help: false };
|
|
82
125
|
}
|
|
83
126
|
|
|
84
|
-
async function
|
|
127
|
+
async function ensureTargetDirReady(targetDir) {
|
|
85
128
|
try {
|
|
86
129
|
const stat = await fs.stat(targetDir);
|
|
87
130
|
if (!stat.isDirectory()) {
|
|
88
131
|
throw new Error(`目标路径已存在且不是目录:${targetDir}`);
|
|
89
132
|
}
|
|
90
|
-
const entries = await fs.readdir(targetDir);
|
|
91
|
-
if (entries.length > 0) {
|
|
92
|
-
throw new Error(`目标目录已存在且非空:${targetDir}`);
|
|
93
|
-
}
|
|
94
133
|
} catch (error) {
|
|
95
134
|
if (error && typeof error === "object" && error.code === "ENOENT") {
|
|
135
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
96
136
|
return;
|
|
97
137
|
}
|
|
98
138
|
throw error;
|
|
@@ -116,6 +156,45 @@ async function updatePackageName(targetDir, port) {
|
|
|
116
156
|
await fs.writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
117
157
|
}
|
|
118
158
|
|
|
159
|
+
async function updateProcessComposePort(targetDir, port) {
|
|
160
|
+
if (port === undefined) return;
|
|
161
|
+
|
|
162
|
+
const filePath = path.join(targetDir, "process-compose.yaml");
|
|
163
|
+
|
|
164
|
+
let raw;
|
|
165
|
+
try {
|
|
166
|
+
raw = await fs.readFile(filePath, "utf8");
|
|
167
|
+
} catch (error) {
|
|
168
|
+
if (error && typeof error === "object" && error.code === "ENOENT") {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const next = raw.replace(
|
|
175
|
+
/^(\s*-\s*["']?PORT=)\d+(["']?\s*)$/m,
|
|
176
|
+
`$1${port}$2`,
|
|
177
|
+
);
|
|
178
|
+
await fs.writeFile(filePath, next);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function updateDefaultTheme(targetDir, theme) {
|
|
182
|
+
if (theme === undefined) return;
|
|
183
|
+
|
|
184
|
+
const filePath = path.join(targetDir, "lib", "theme", "default-theme.ts");
|
|
185
|
+
const raw = await fs.readFile(filePath, "utf8");
|
|
186
|
+
const next = raw.replace(
|
|
187
|
+
/(export const DEFAULT_THEME_STYLE:\s*ThemeStyle\s*=\s*")[^"]+(";\s*)/u,
|
|
188
|
+
`$1${theme}$2`,
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
if (next === raw) {
|
|
192
|
+
throw new Error(`未能更新默认主题,请检查文件:${filePath}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
await fs.writeFile(filePath, next);
|
|
196
|
+
}
|
|
197
|
+
|
|
119
198
|
function runCommand(command, args, options) {
|
|
120
199
|
return new Promise((resolve, reject) => {
|
|
121
200
|
const child = spawn(command, args, { stdio: "inherit", ...options });
|
|
@@ -133,6 +212,36 @@ function isCommandMissingError(error) {
|
|
|
133
212
|
);
|
|
134
213
|
}
|
|
135
214
|
|
|
215
|
+
const INITIAL_COMMIT_MESSAGE = "Initial commit";
|
|
216
|
+
|
|
217
|
+
async function initGit(targetDir) {
|
|
218
|
+
try {
|
|
219
|
+
const initCode = await runCommand("git", ["init"], { cwd: targetDir });
|
|
220
|
+
if (initCode !== 0) return false;
|
|
221
|
+
|
|
222
|
+
const addCode = await runCommand("git", ["add", "."], { cwd: targetDir });
|
|
223
|
+
if (addCode !== 0) {
|
|
224
|
+
console.log("git add 未成功,跳过 git commit\n");
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const commitCode = await runCommand(
|
|
229
|
+
"git",
|
|
230
|
+
["commit", "-m", INITIAL_COMMIT_MESSAGE],
|
|
231
|
+
{ cwd: targetDir },
|
|
232
|
+
);
|
|
233
|
+
if (commitCode === 0) {
|
|
234
|
+
console.log("已执行 git init、git add、git commit\n");
|
|
235
|
+
} else {
|
|
236
|
+
console.log("git commit 未成功(如未配置 user.name/user.email 可稍后手动提交)\n");
|
|
237
|
+
}
|
|
238
|
+
return true;
|
|
239
|
+
} catch (_error) {
|
|
240
|
+
// 不存在 git 或其它异常时静默跳过,不报错
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
136
245
|
async function installDependencies(targetDir) {
|
|
137
246
|
console.log("\n正在安装依赖(优先 pnpm)...\n");
|
|
138
247
|
|
|
@@ -178,14 +287,21 @@ async function main() {
|
|
|
178
287
|
return;
|
|
179
288
|
}
|
|
180
289
|
|
|
181
|
-
const { projectDir, port } = parsed;
|
|
290
|
+
const { projectDir, port, theme } = parsed;
|
|
182
291
|
const targetDir = path.resolve(process.cwd(), projectDir);
|
|
183
292
|
|
|
184
|
-
await
|
|
185
|
-
await fs.mkdir(targetDir, { recursive: true });
|
|
293
|
+
await ensureTargetDirReady(targetDir);
|
|
186
294
|
|
|
187
|
-
await fs.cp(TEMPLATE_DIR, targetDir, {
|
|
295
|
+
await fs.cp(TEMPLATE_DIR, targetDir, {
|
|
296
|
+
recursive: true,
|
|
297
|
+
force: true,
|
|
298
|
+
errorOnExist: false,
|
|
299
|
+
});
|
|
188
300
|
await updatePackageName(targetDir, port);
|
|
301
|
+
await updateProcessComposePort(targetDir, port);
|
|
302
|
+
await updateDefaultTheme(targetDir, theme);
|
|
303
|
+
|
|
304
|
+
await initGit(targetDir);
|
|
189
305
|
|
|
190
306
|
const installResult = await installDependencies(targetDir);
|
|
191
307
|
if (!installResult.ok) {
|
|
@@ -204,6 +320,9 @@ async function main() {
|
|
|
204
320
|
if (port !== undefined) {
|
|
205
321
|
console.log(`已设置默认端口:${port}(写入 dev/start 启动命令)`);
|
|
206
322
|
}
|
|
323
|
+
if (theme !== undefined) {
|
|
324
|
+
console.log(`已设置默认主题:${theme}`);
|
|
325
|
+
}
|
|
207
326
|
console.log("\n下一步:");
|
|
208
327
|
console.log(` cd ${projectDir}`);
|
|
209
328
|
if (installResult.installer === "npm") {
|
package/package.json
CHANGED
package/template/AGENTS.md
CHANGED
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
## 3) 常用命令(pnpm)
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
本项目默认**优先使用 pnpm** 安装依赖;若环境受限可使用 npm 作为回退方案(见 `package.json` 的 `packageManager` / `engines`)。
|
|
45
45
|
|
|
46
46
|
以仓库根目录为工作目录:
|
|
47
47
|
|
|
@@ -144,3 +144,82 @@
|
|
|
144
144
|
- 确认 `tailwind.config.mjs` 的 `content` 覆盖到了 `components/ui` 等目录
|
|
145
145
|
- 构建报 Turbopack/受限环境问题
|
|
146
146
|
- 当前 `pnpm build` 已固定使用 `next build --webpack`(见 `package.json`)
|
|
147
|
+
|
|
148
|
+
## 13) Docs-First 工作流(强约束,模板默认)
|
|
149
|
+
|
|
150
|
+
本模板默认与 `ibuild + idesigner + igen-*` agents 配合。以下规则是**必须执行**,不是建议。
|
|
151
|
+
|
|
152
|
+
- 状态真相源只有一个:`docs/project_state.json`。
|
|
153
|
+
- `docs/index.md` 仅作导航与摘要,允许滞后,不能作为阶段判定依据。
|
|
154
|
+
- 所有实现必须可回溯到 docs;禁止“先写代码、后补文档”的反向流程。
|
|
155
|
+
|
|
156
|
+
### 13.1 文档缺失处理(必须)
|
|
157
|
+
|
|
158
|
+
- 若用户请求“生成项目/落地开发”,但 `docs/` 不完整:
|
|
159
|
+
1. 先补齐 docs,再进入代码实现。
|
|
160
|
+
2. 补齐顺序固定:`igen-prd -> igen-persona -> igen-feature-modules -> igen-style-guide -> igen-db-schema`。
|
|
161
|
+
3. 完成后更新 `docs/project_state.json`(`docs_ready=true`)再进入实现。
|
|
162
|
+
|
|
163
|
+
### 13.2 实现前必读清单(按范围)
|
|
164
|
+
|
|
165
|
+
- 前端改动(页面/交互/样式)前,必须读取:
|
|
166
|
+
- `docs/prd/prd.md`
|
|
167
|
+
- `docs/feature_plan/feature_modules.md` + 对应 `feature_module_*.md`
|
|
168
|
+
- `docs/style_guide/*.style-guide.md`
|
|
169
|
+
- `docs/implementation/frontend_mock_scope.md`
|
|
170
|
+
- `docs/codegen_contract.md`
|
|
171
|
+
- 后端改动(API/DB/数据流)前,必须读取:
|
|
172
|
+
- `docs/prd/prd.md`
|
|
173
|
+
- `docs/feature_plan/feature_modules.md` + 对应 `feature_module_*.md`
|
|
174
|
+
- `docs/db/db_schema.md` + `docs/db/db_schema_core.md`
|
|
175
|
+
- `docs/db/mock_data_mapping.md`
|
|
176
|
+
- `docs/implementation/backend_core_scope.md`
|
|
177
|
+
- `docs/codegen_contract.md`
|
|
178
|
+
|
|
179
|
+
### 13.3 冲突处理规则(docs vs 当前代码/需求)
|
|
180
|
+
|
|
181
|
+
- 默认优先级:`docs/project_state.json` + docs 契约 > 现有实现细节 > 记忆/猜测。
|
|
182
|
+
- 若用户明确要求偏离 docs:先更新 docs,再改代码;禁止只改代码不更新 docs。
|
|
183
|
+
- 若 docs 内部自相矛盾:先修 docs 再实现;不能在矛盾状态下继续大规模开发。
|
|
184
|
+
|
|
185
|
+
### 13.4 阶段推进规则(禁止“建议即停止”)
|
|
186
|
+
|
|
187
|
+
- `docs_ready=true` 后,默认连续推进 Stage B -> Stage C。
|
|
188
|
+
- 仅在真实阻塞(密钥/权限/外部依赖缺失)时停止并向用户提问。
|
|
189
|
+
- 禁止以“立即启动开发/推荐阅读顺序/命令清单”替代实际执行。
|
|
190
|
+
- 若应用未运行,必须主动启动(优先 `restart_workflow(name="web")`),而不是让用户手动执行 `pnpm dev`。
|
|
191
|
+
|
|
192
|
+
## 14) 文档一致性门禁(完成前必须全部通过)
|
|
193
|
+
|
|
194
|
+
### 14.1 路由与模块一致性
|
|
195
|
+
|
|
196
|
+
- 页面路由需与 `docs/feature_plan/feature_module_*.md` 的页面清单一致。
|
|
197
|
+
- API 路径需与 docs 规划和 `shared/routes.ts` 契约一致。
|
|
198
|
+
- 禁止新增 docs 未定义的核心页面/API(除非先更新 docs)。
|
|
199
|
+
|
|
200
|
+
### 14.2 数据契约一致性
|
|
201
|
+
|
|
202
|
+
- Stage B Mock 字段必须与 `docs/db/mock_data_mapping.md` 对齐。
|
|
203
|
+
- Stage C API/DB 字段必须与 `docs/db/*.md` 对齐。
|
|
204
|
+
- 返回数据需按 `shared/routes.ts` 对应 zod schema 解析/校验。
|
|
205
|
+
|
|
206
|
+
### 14.3 运行与重定向安全
|
|
207
|
+
|
|
208
|
+
- 禁止自重定向或重定向环(例如 `/` -> `/`)。
|
|
209
|
+
- 验证关键路由时,重定向链长度必须有界(建议 <= 3)。
|
|
210
|
+
- `/`, `/spots`, `/catches`, `/community`, `/profile`, `/hello` 不得出现 500 或循环跳转。
|
|
211
|
+
|
|
212
|
+
### 14.4 质量门禁
|
|
213
|
+
|
|
214
|
+
- `pnpm check` 通过。
|
|
215
|
+
- `app/api` 与 `server` 不允许残留阻塞性占位实现(如 `TODO: Implement`)。
|
|
216
|
+
- 未通过门禁前,`docs/project_state.json` 不能标记对应阶段为 `completed`。
|
|
217
|
+
|
|
218
|
+
## 15) 交付与同步要求(模板仓库)
|
|
219
|
+
|
|
220
|
+
- 每次阶段状态变更后,同步更新:
|
|
221
|
+
- `docs/project_state.json`(真相源)
|
|
222
|
+
- `docs/index.md`(派生状态展示)
|
|
223
|
+
- 输出总结时必须给出“文档溯源”:
|
|
224
|
+
- 本次实现对应了哪些 docs 文件(至少列出路径)。
|
|
225
|
+
- 若有偏差,说明已更新的 docs 路径。
|
package/template/README.md
CHANGED
|
@@ -14,8 +14,6 @@ pnpm dev
|
|
|
14
14
|
bun dev
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
18
|
-
|
|
19
17
|
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
|
20
18
|
|
|
21
19
|
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
|
@@ -309,7 +309,7 @@ export function DevPreviewShield({ children }: { children: React.ReactNode }) {
|
|
|
309
309
|
}, [clearTimer]);
|
|
310
310
|
|
|
311
311
|
const handleBuildOk = useCallback(() => {
|
|
312
|
-
const
|
|
312
|
+
const hadVisibleOverlay = overlayRef.current !== "none";
|
|
313
313
|
|
|
314
314
|
clearTimer(showTimerRef);
|
|
315
315
|
clearTimer(hideTimerRef);
|
|
@@ -317,15 +317,15 @@ export function DevPreviewShield({ children }: { children: React.ReactNode }) {
|
|
|
317
317
|
setDebugMode(false);
|
|
318
318
|
setResetKey((k) => k + 1);
|
|
319
319
|
|
|
320
|
-
if (
|
|
321
|
-
showToast();
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (overlayRef.current === "none") {
|
|
320
|
+
if (!hadVisibleOverlay) {
|
|
325
321
|
setErrorInfo(null);
|
|
326
322
|
return;
|
|
327
323
|
}
|
|
328
324
|
|
|
325
|
+
if (!debugModeRef.current) {
|
|
326
|
+
showToast();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
329
|
hideOverlayWithMinVisible();
|
|
330
330
|
}, [clearTimer, hideOverlayWithMinVisible, showToast]);
|
|
331
331
|
|
package/template/app/globals.css
CHANGED
|
@@ -113,6 +113,297 @@
|
|
|
113
113
|
--badge-outline: hsl(var(--border));
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/* Theme style presets (used by html[data-theme-style="<preset>"]) */
|
|
117
|
+
:root[data-theme-style="quadratic"] {
|
|
118
|
+
--background: 240 8.3% 95.3%;
|
|
119
|
+
--foreground: 225 14.3% 5.5%;
|
|
120
|
+
|
|
121
|
+
--card: 0 0% 100%;
|
|
122
|
+
--card-foreground: 225 14.3% 5.5%;
|
|
123
|
+
--popover: 0 0% 100%;
|
|
124
|
+
--popover-foreground: 225 14.3% 5.5%;
|
|
125
|
+
|
|
126
|
+
--primary: 240 8.6% 93.1%;
|
|
127
|
+
--primary-foreground: 225 14.3% 5.5%;
|
|
128
|
+
--secondary: 240 7% 86.1%;
|
|
129
|
+
--secondary-foreground: 225 14.3% 5.5%;
|
|
130
|
+
--muted: 240 8.6% 93.1%;
|
|
131
|
+
--muted-foreground: 225 7% 35%;
|
|
132
|
+
--accent: 240 7% 86.1%;
|
|
133
|
+
--accent-foreground: 225 14.3% 5.5%;
|
|
134
|
+
|
|
135
|
+
--border: 240 7% 82%;
|
|
136
|
+
--input: 240 7% 82%;
|
|
137
|
+
--ring: 225 14.3% 5.5%;
|
|
138
|
+
|
|
139
|
+
--chart-1: 225 14.3% 35%;
|
|
140
|
+
--chart-2: 240 8% 55%;
|
|
141
|
+
--chart-3: 220 40% 55%;
|
|
142
|
+
--chart-4: 270 20% 62%;
|
|
143
|
+
--chart-5: 190 30% 52%;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.dark[data-theme-style="quadratic"] {
|
|
147
|
+
--background: 225 14.3% 5.5%;
|
|
148
|
+
--foreground: 240 8.3% 95.3%;
|
|
149
|
+
|
|
150
|
+
--card: 225 12% 9%;
|
|
151
|
+
--card-foreground: 240 8.3% 95.3%;
|
|
152
|
+
--popover: 225 12% 9%;
|
|
153
|
+
--popover-foreground: 240 8.3% 95.3%;
|
|
154
|
+
|
|
155
|
+
--primary: 240 8.6% 93.1%;
|
|
156
|
+
--primary-foreground: 225 14.3% 5.5%;
|
|
157
|
+
--secondary: 225 8% 15%;
|
|
158
|
+
--secondary-foreground: 240 8.3% 95.3%;
|
|
159
|
+
--muted: 225 8% 12%;
|
|
160
|
+
--muted-foreground: 240 7% 70%;
|
|
161
|
+
--accent: 225 8% 12%;
|
|
162
|
+
--accent-foreground: 240 8.3% 95.3%;
|
|
163
|
+
|
|
164
|
+
--border: 225 8% 22%;
|
|
165
|
+
--input: 225 8% 22%;
|
|
166
|
+
--ring: 240 8.6% 93.1%;
|
|
167
|
+
|
|
168
|
+
--chart-1: 240 8.6% 70%;
|
|
169
|
+
--chart-2: 220 30% 65%;
|
|
170
|
+
--chart-3: 190 30% 60%;
|
|
171
|
+
--chart-4: 270 20% 65%;
|
|
172
|
+
--chart-5: 45 20% 62%;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
:root[data-theme-style="nomad"] {
|
|
176
|
+
--background: 240 9.1% 95.7%;
|
|
177
|
+
--foreground: 220 12.5% 9.4%;
|
|
178
|
+
|
|
179
|
+
--card: 240 12% 98%;
|
|
180
|
+
--card-foreground: 220 12.5% 9.4%;
|
|
181
|
+
--popover: 240 12% 98%;
|
|
182
|
+
--popover-foreground: 220 12.5% 9.4%;
|
|
183
|
+
|
|
184
|
+
--primary: 339 89.8% 53.9%;
|
|
185
|
+
--primary-foreground: 220 12.5% 9.4%;
|
|
186
|
+
--secondary: 231 10.4% 86.9%;
|
|
187
|
+
--secondary-foreground: 220 12.5% 9.4%;
|
|
188
|
+
--muted: 240 9% 92%;
|
|
189
|
+
--muted-foreground: 220 8% 35%;
|
|
190
|
+
--accent: 231 10.4% 86.9%;
|
|
191
|
+
--accent-foreground: 220 12.5% 9.4%;
|
|
192
|
+
|
|
193
|
+
--border: 231 10% 82%;
|
|
194
|
+
--input: 231 10% 82%;
|
|
195
|
+
--ring: 339 89.8% 53.9%;
|
|
196
|
+
|
|
197
|
+
--chart-1: 339 89.8% 53.9%;
|
|
198
|
+
--chart-2: 220 28% 40%;
|
|
199
|
+
--chart-3: 40 72% 60%;
|
|
200
|
+
--chart-4: 173 25% 45%;
|
|
201
|
+
--chart-5: 280 45% 60%;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.dark[data-theme-style="nomad"] {
|
|
205
|
+
--background: 220 12.5% 9.4%;
|
|
206
|
+
--foreground: 240 9.1% 95.7%;
|
|
207
|
+
|
|
208
|
+
--card: 220 12% 12%;
|
|
209
|
+
--card-foreground: 240 9.1% 95.7%;
|
|
210
|
+
--popover: 220 12% 12%;
|
|
211
|
+
--popover-foreground: 240 9.1% 95.7%;
|
|
212
|
+
|
|
213
|
+
--primary: 339 90% 62%;
|
|
214
|
+
--primary-foreground: 220 12.5% 9.4%;
|
|
215
|
+
--secondary: 220 10% 17%;
|
|
216
|
+
--secondary-foreground: 240 9.1% 95.7%;
|
|
217
|
+
--muted: 220 9% 14%;
|
|
218
|
+
--muted-foreground: 240 7% 70%;
|
|
219
|
+
--accent: 220 9% 14%;
|
|
220
|
+
--accent-foreground: 240 9.1% 95.7%;
|
|
221
|
+
|
|
222
|
+
--border: 220 8% 22%;
|
|
223
|
+
--input: 220 8% 22%;
|
|
224
|
+
--ring: 339 90% 62%;
|
|
225
|
+
|
|
226
|
+
--chart-1: 339 90% 66%;
|
|
227
|
+
--chart-2: 40 72% 65%;
|
|
228
|
+
--chart-3: 173 30% 58%;
|
|
229
|
+
--chart-4: 280 50% 72%;
|
|
230
|
+
--chart-5: 220 18% 72%;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
:root[data-theme-style="honey"] {
|
|
234
|
+
--background: 49 38.1% 91.8%;
|
|
235
|
+
--foreground: 40 52.9% 27.5%;
|
|
236
|
+
|
|
237
|
+
--card: 49 42% 95%;
|
|
238
|
+
--card-foreground: 40 52.9% 27.5%;
|
|
239
|
+
--popover: 49 42% 95%;
|
|
240
|
+
--popover-foreground: 40 52.9% 27.5%;
|
|
241
|
+
|
|
242
|
+
--primary: 40 72.8% 68.2%;
|
|
243
|
+
--primary-foreground: 40 52.9% 18%;
|
|
244
|
+
--secondary: 63 20.8% 79.2%;
|
|
245
|
+
--secondary-foreground: 40 52.9% 27.5%;
|
|
246
|
+
--muted: 49 30% 88%;
|
|
247
|
+
--muted-foreground: 40 24% 38%;
|
|
248
|
+
--accent: 63 20.8% 79.2%;
|
|
249
|
+
--accent-foreground: 40 52.9% 27.5%;
|
|
250
|
+
|
|
251
|
+
--border: 52 22% 74%;
|
|
252
|
+
--input: 52 22% 74%;
|
|
253
|
+
--ring: 40 72.8% 68.2%;
|
|
254
|
+
|
|
255
|
+
--chart-1: 40 72.8% 55%;
|
|
256
|
+
--chart-2: 63 30% 45%;
|
|
257
|
+
--chart-3: 173 25% 42%;
|
|
258
|
+
--chart-4: 18 56% 50%;
|
|
259
|
+
--chart-5: 240 16% 52%;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.dark[data-theme-style="honey"] {
|
|
263
|
+
--background: 36 38% 10%;
|
|
264
|
+
--foreground: 49 30% 88%;
|
|
265
|
+
|
|
266
|
+
--card: 34 30% 14%;
|
|
267
|
+
--card-foreground: 49 30% 88%;
|
|
268
|
+
--popover: 34 30% 14%;
|
|
269
|
+
--popover-foreground: 49 30% 88%;
|
|
270
|
+
|
|
271
|
+
--primary: 40 72.8% 68.2%;
|
|
272
|
+
--primary-foreground: 36 38% 10%;
|
|
273
|
+
--secondary: 38 20% 20%;
|
|
274
|
+
--secondary-foreground: 49 30% 88%;
|
|
275
|
+
--muted: 38 18% 18%;
|
|
276
|
+
--muted-foreground: 49 18% 70%;
|
|
277
|
+
--accent: 38 18% 18%;
|
|
278
|
+
--accent-foreground: 49 30% 88%;
|
|
279
|
+
|
|
280
|
+
--border: 38 18% 26%;
|
|
281
|
+
--input: 38 18% 26%;
|
|
282
|
+
--ring: 40 72.8% 68.2%;
|
|
283
|
+
|
|
284
|
+
--chart-1: 40 72.8% 68.2%;
|
|
285
|
+
--chart-2: 63 35% 58%;
|
|
286
|
+
--chart-3: 173 30% 56%;
|
|
287
|
+
--chart-4: 20 56% 64%;
|
|
288
|
+
--chart-5: 240 22% 70%;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
:root[data-theme-style="zen-garden"] {
|
|
292
|
+
--background: 84 9.8% 90%;
|
|
293
|
+
--foreground: 225 18.2% 8.6%;
|
|
294
|
+
|
|
295
|
+
--card: 84 12% 94%;
|
|
296
|
+
--card-foreground: 225 18.2% 8.6%;
|
|
297
|
+
--popover: 84 12% 94%;
|
|
298
|
+
--popover-foreground: 225 18.2% 8.6%;
|
|
299
|
+
|
|
300
|
+
--primary: 173 24.7% 62%;
|
|
301
|
+
--primary-foreground: 225 18.2% 8.6%;
|
|
302
|
+
--secondary: 289 32.9% 72%;
|
|
303
|
+
--secondary-foreground: 225 18.2% 8.6%;
|
|
304
|
+
--muted: 84 10% 86%;
|
|
305
|
+
--muted-foreground: 225 10% 36%;
|
|
306
|
+
--accent: 289 32.9% 72%;
|
|
307
|
+
--accent-foreground: 225 18.2% 8.6%;
|
|
308
|
+
|
|
309
|
+
--border: 84 8% 78%;
|
|
310
|
+
--input: 84 8% 78%;
|
|
311
|
+
--ring: 173 24.7% 62%;
|
|
312
|
+
|
|
313
|
+
--chart-1: 173 24.7% 48%;
|
|
314
|
+
--chart-2: 289 32.9% 58%;
|
|
315
|
+
--chart-3: 40 68% 56%;
|
|
316
|
+
--chart-4: 220 26% 50%;
|
|
317
|
+
--chart-5: 0 55% 58%;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.dark[data-theme-style="zen-garden"] {
|
|
321
|
+
--background: 225 18.2% 8.6%;
|
|
322
|
+
--foreground: 84 9.8% 90%;
|
|
323
|
+
|
|
324
|
+
--card: 225 16% 12%;
|
|
325
|
+
--card-foreground: 84 9.8% 90%;
|
|
326
|
+
--popover: 225 16% 12%;
|
|
327
|
+
--popover-foreground: 84 9.8% 90%;
|
|
328
|
+
|
|
329
|
+
--primary: 173 30% 66%;
|
|
330
|
+
--primary-foreground: 225 18.2% 8.6%;
|
|
331
|
+
--secondary: 225 12% 18%;
|
|
332
|
+
--secondary-foreground: 84 9.8% 90%;
|
|
333
|
+
--muted: 225 10% 15%;
|
|
334
|
+
--muted-foreground: 84 8% 72%;
|
|
335
|
+
--accent: 225 10% 15%;
|
|
336
|
+
--accent-foreground: 84 9.8% 90%;
|
|
337
|
+
|
|
338
|
+
--border: 225 10% 24%;
|
|
339
|
+
--input: 225 10% 24%;
|
|
340
|
+
--ring: 173 30% 66%;
|
|
341
|
+
|
|
342
|
+
--chart-1: 173 30% 66%;
|
|
343
|
+
--chart-2: 289 36% 70%;
|
|
344
|
+
--chart-3: 40 68% 64%;
|
|
345
|
+
--chart-4: 220 30% 70%;
|
|
346
|
+
--chart-5: 355 65% 68%;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
:root[data-theme-style="highlighter"] {
|
|
350
|
+
--background: 228 23.8% 95.9%;
|
|
351
|
+
--foreground: 223 18.9% 7.3%;
|
|
352
|
+
|
|
353
|
+
--card: 228 24% 98%;
|
|
354
|
+
--card-foreground: 223 18.9% 7.3%;
|
|
355
|
+
--popover: 228 24% 98%;
|
|
356
|
+
--popover-foreground: 223 18.9% 7.3%;
|
|
357
|
+
|
|
358
|
+
--primary: 97 70.5% 64.1%;
|
|
359
|
+
--primary-foreground: 223 18.9% 7.3%;
|
|
360
|
+
--secondary: 249 35.6% 88.4%;
|
|
361
|
+
--secondary-foreground: 223 18.9% 7.3%;
|
|
362
|
+
--muted: 228 20% 92%;
|
|
363
|
+
--muted-foreground: 223 10% 35%;
|
|
364
|
+
--accent: 249 35.6% 88.4%;
|
|
365
|
+
--accent-foreground: 223 18.9% 7.3%;
|
|
366
|
+
|
|
367
|
+
--border: 238 20% 84%;
|
|
368
|
+
--input: 238 20% 84%;
|
|
369
|
+
--ring: 97 70.5% 64.1%;
|
|
370
|
+
|
|
371
|
+
--chart-1: 97 70.5% 48%;
|
|
372
|
+
--chart-2: 249 45% 56%;
|
|
373
|
+
--chart-3: 202 72% 54%;
|
|
374
|
+
--chart-4: 339 78% 58%;
|
|
375
|
+
--chart-5: 40 78% 58%;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.dark[data-theme-style="highlighter"] {
|
|
379
|
+
--background: 223 18.9% 7.3%;
|
|
380
|
+
--foreground: 228 23.8% 95.9%;
|
|
381
|
+
|
|
382
|
+
--card: 223 16% 11%;
|
|
383
|
+
--card-foreground: 228 23.8% 95.9%;
|
|
384
|
+
--popover: 223 16% 11%;
|
|
385
|
+
--popover-foreground: 228 23.8% 95.9%;
|
|
386
|
+
|
|
387
|
+
--primary: 97 74% 66%;
|
|
388
|
+
--primary-foreground: 223 18.9% 7.3%;
|
|
389
|
+
--secondary: 223 12% 18%;
|
|
390
|
+
--secondary-foreground: 228 23.8% 95.9%;
|
|
391
|
+
--muted: 223 10% 15%;
|
|
392
|
+
--muted-foreground: 228 14% 72%;
|
|
393
|
+
--accent: 223 10% 15%;
|
|
394
|
+
--accent-foreground: 228 23.8% 95.9%;
|
|
395
|
+
|
|
396
|
+
--border: 223 10% 24%;
|
|
397
|
+
--input: 223 10% 24%;
|
|
398
|
+
--ring: 97 74% 66%;
|
|
399
|
+
|
|
400
|
+
--chart-1: 97 74% 66%;
|
|
401
|
+
--chart-2: 249 50% 72%;
|
|
402
|
+
--chart-3: 202 78% 70%;
|
|
403
|
+
--chart-4: 339 80% 70%;
|
|
404
|
+
--chart-5: 40 78% 68%;
|
|
405
|
+
}
|
|
406
|
+
|
|
116
407
|
@layer base {
|
|
117
408
|
* {
|
|
118
409
|
border-color: hsl(var(--border));
|
package/template/app/layout.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
|
|
|
2
2
|
import "./globals.css";
|
|
3
3
|
import { DevPreviewShield } from "./_components/DevPreviewShield";
|
|
4
4
|
import { Providers } from "./providers";
|
|
5
|
+
import { DEFAULT_THEME_STYLE } from "@/lib/theme/default-theme";
|
|
5
6
|
|
|
6
7
|
export const metadata: Metadata = {
|
|
7
8
|
title: "Create Next App",
|
|
@@ -14,7 +15,11 @@ export default function RootLayout({
|
|
|
14
15
|
children: React.ReactNode;
|
|
15
16
|
}>) {
|
|
16
17
|
return (
|
|
17
|
-
<html
|
|
18
|
+
<html
|
|
19
|
+
lang="zh-CN"
|
|
20
|
+
suppressHydrationWarning
|
|
21
|
+
data-theme-style={DEFAULT_THEME_STYLE}
|
|
22
|
+
>
|
|
18
23
|
<body className="antialiased">
|
|
19
24
|
<Providers>
|
|
20
25
|
{process.env.NODE_ENV === "development" ? (
|
package/template/package.json
CHANGED
|
@@ -2,14 +2,9 @@
|
|
|
2
2
|
"name": "nextjs-app",
|
|
3
3
|
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
|
-
"packageManager": "pnpm@9",
|
|
6
|
-
"engines": {
|
|
7
|
-
"packageManager": "pnpm@>=9"
|
|
8
|
-
},
|
|
9
5
|
"scripts": {
|
|
10
|
-
"preinstall": "npx only-allow pnpm",
|
|
11
6
|
"dev": "next dev",
|
|
12
|
-
"build": "next build
|
|
7
|
+
"build": "next build",
|
|
13
8
|
"start": "next start",
|
|
14
9
|
"check": "tsc -p tsconfig.json --noEmit",
|
|
15
10
|
"db:push": "drizzle-kit push",
|