@icebreakers/monorepo-templates 2.0.6 → 2.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.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/assets/.agents/skills/repoctl/SKILL.md +2 -2
- package/assets/.agents/skills/repoctl/references/templates.md +3 -2
- package/assets/.github/workflows/ci.yml +0 -4
- package/assets/.github/workflows/release.yml +5 -0
- package/assets/package.json +3 -7
- package/assets/pnpm-workspace.yaml +2 -0
- package/assets/turbo.json +11 -4
- package/dist/cli.mjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{prepare-BapI8ioj.mjs → prepare-2VvFwYDz.mjs} +23 -3
- package/package.json +1 -1
- package/template-data.mjs +8 -0
- package/templates/client/package.json +1 -1
- package/templates/nimbus/AGENTS.md +12 -0
- package/templates/nimbus/LICENSE +21 -0
- package/templates/nimbus/README.md +17 -0
- package/templates/nimbus/UPSTREAM.md +16 -0
- package/templates/nimbus/astro.config.ts +28 -0
- package/templates/nimbus/eslint.config.js +25 -0
- package/templates/nimbus/gitignore +5 -0
- package/templates/nimbus/nimbus.json +4 -0
- package/templates/nimbus/package.json +34 -0
- package/templates/nimbus/public/favicon.svg +1 -0
- package/templates/nimbus/scripts/check-locales.mjs +11 -0
- package/templates/nimbus/src/components/aside.astro +9 -0
- package/templates/nimbus/src/components/head.astro +43 -0
- package/templates/nimbus/src/components/search/client.ts +62 -0
- package/templates/nimbus/src/components/search/index.astro +26 -0
- package/templates/nimbus/src/components/sidebar.astro +26 -0
- package/templates/nimbus/src/components.ts +3 -0
- package/templates/nimbus/src/content/docs/get-started.mdx +36 -0
- package/templates/nimbus/src/content/docs/index.mdx +16 -0
- package/templates/nimbus/src/content/docs/writing.mdx +35 -0
- package/templates/nimbus/src/content/docs/zh/get-started.mdx +36 -0
- package/templates/nimbus/src/content/docs/zh/index.mdx +16 -0
- package/templates/nimbus/src/content/docs/zh/writing.mdx +35 -0
- package/templates/nimbus/src/content.config.ts +6 -0
- package/templates/nimbus/src/env.d.ts +6 -0
- package/templates/nimbus/src/layouts/docs.astro +70 -0
- package/templates/nimbus/src/lib/locale.ts +50 -0
- package/templates/nimbus/src/pages/[...slug]/index.md.ts +4 -0
- package/templates/nimbus/src/pages/[...slug]/index.mdx.ts +4 -0
- package/templates/nimbus/src/pages/[...slug].astro +36 -0
- package/templates/nimbus/src/pages/[section]/llms.txt.ts +4 -0
- package/templates/nimbus/src/pages/llms-full.txt.ts +4 -0
- package/templates/nimbus/src/pages/llms.txt.ts +4 -0
- package/templates/nimbus/src/pages/robots.txt.ts +18 -0
- package/templates/nimbus/src/styles/base.css +121 -0
- package/templates/nimbus/src/styles/site.css +186 -0
- package/templates/nimbus/stylelint.config.js +3 -0
- package/templates/nimbus/tsconfig.json +10 -0
- package/templates/server/package.json +1 -1
- package/templates/vitepress/.vitepress/config.ts +4 -5
- package/templates/vitepress/.vitepress/home/content.ts +2 -2
- package/templates/vitepress/.vitepress/home/faq.ts +16 -0
- package/templates/vitepress/.vitepress/mermaid/markdown.ts +18 -0
- package/templates/vitepress/.vitepress/mermaid/mermaid.vue +66 -0
- package/templates/vitepress/.vitepress/mermaid/render.ts +37 -0
- package/templates/vitepress/.vitepress/seo.ts +12 -1
- package/templates/vitepress/.vitepress/theme/components/HomePage.vue +2 -16
- package/templates/vitepress/.vitepress/theme/index.ts +3 -1
- package/templates/vitepress/ai/create.md +1 -1
- package/templates/vitepress/package.json +4 -8
- package/templates/vitepress/reference/commands.md +3 -3
- package/templates/vitepress/reference/template-assets.md +1 -1
- package/templates/vitepress/reference/templates.md +13 -9
- package/templates/vitepress/tasks/index.md +1 -1
- package/templates/vitepress/tasks/release.md +18 -0
- package/templates/vitepress/test/mermaid.test.ts +39 -0
- package/templates/vitepress/test/render.test.ts +48 -0
- package/templates/vitepress/test/seo.test.ts +19 -0
- package/templates/vitepress/tsconfig.json +8 -8
- package/templates/vitepress/vitest.config.ts +8 -0
- package/templates/vitepress/zh/ai/create.md +1 -1
- package/templates/vitepress/zh/learn/monorepo/manage.md +1 -1
- package/templates/vitepress/zh/reference/commands.md +3 -3
- package/templates/vitepress/zh/reference/execution-model.md +1 -1
- package/templates/vitepress/zh/reference/template-assets.md +3 -2
- package/templates/vitepress/zh/reference/templates.md +13 -9
- package/templates/vitepress/zh/tasks/index.md +1 -1
- package/templates/vitepress/zh/tasks/release.md +18 -0
- package/templates/vitepress/zh/tasks/reports.md +1 -1
- package/assets/.changeset/wicked-ravens-wonder.md +0 -5
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from '@icebreakers/monorepo-templates'
|
|
19
19
|
|
|
20
20
|
const libraries = getTemplateChoices({ category: 'library' })
|
|
21
|
-
const
|
|
21
|
+
const nimbus = getTemplateDefinition('nimbus')
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
The source workspaces under the repository's `templates/` directory are private. This package is their supported distribution boundary.
|
package/README.zh-CN.md
CHANGED
|
@@ -10,7 +10,7 @@ repoctl 的内置项目模板和受管工作区资产包。
|
|
|
10
10
|
import { getTemplateChoices, getTemplateDefinition } from '@icebreakers/monorepo-templates'
|
|
11
11
|
|
|
12
12
|
const libraries = getTemplateChoices({ category: 'library' })
|
|
13
|
-
const
|
|
13
|
+
const nimbus = getTemplateDefinition('nimbus')
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
仓库 `templates/` 下的源码工作区均为私有,本包是这些模板的正式分发边界。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: repoctl
|
|
3
|
-
description: Create and maintain pnpm/Turborepo workspaces with repoctl. Use when the user says 使用 repoctl 创建项目, create a monorepo, pnpm create repoctl@latest, scaffold Vue/Hono/tsdown/
|
|
3
|
+
description: Create and maintain pnpm/Turborepo workspaces with repoctl. Use when the user says 使用 repoctl 创建项目, create a monorepo, pnpm create repoctl@latest, scaffold Vue/Hono/tsdown/Nimbus/VitePress, or run repo init/doctor/new/check.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# repoctl
|
|
@@ -32,7 +32,7 @@ pnpm exec repo doctor
|
|
|
32
32
|
| API / Hono service | `hono-server` |
|
|
33
33
|
| TypeScript library / SDK | `tsdown` |
|
|
34
34
|
| Vue component library | `vue-lib` |
|
|
35
|
-
| Documentation site | `
|
|
35
|
+
| Documentation site | `nimbus` |
|
|
36
36
|
| CLI | `cli` |
|
|
37
37
|
| Unspecified | omit `--templates` |
|
|
38
38
|
|
|
@@ -8,7 +8,7 @@ Intent defaults:
|
|
|
8
8
|
- library -> `tsdown` -> `packages/<name>`
|
|
9
9
|
- web-app -> `vue-hono` -> `apps/<name>`
|
|
10
10
|
- api-service -> `hono-server` -> `apps/<name>`
|
|
11
|
-
- docs-site -> `
|
|
11
|
+
- docs-site -> `nimbus` -> `apps/<name>`
|
|
12
12
|
- cli-tool -> `cli` -> `apps/<name>`
|
|
13
13
|
|
|
14
14
|
Run `repo templates` to discover template keys, categories, default targets, and
|
|
@@ -36,7 +36,8 @@ Built-in template map:
|
|
|
36
36
|
- vue-lib -> templates/vue-lib => packages/vue-lib
|
|
37
37
|
- hono-server -> templates/server => apps/server
|
|
38
38
|
- vue-hono -> templates/client => apps/client
|
|
39
|
-
-
|
|
39
|
+
- nimbus -> templates/nimbus => apps/docs (default documentation template)
|
|
40
|
+
- vitepress -> templates/vitepress => apps/website (explicit alternative)
|
|
40
41
|
- cli -> templates/cli => apps/cli
|
|
41
42
|
|
|
42
43
|
Notes:
|
|
@@ -78,10 +78,6 @@ jobs:
|
|
|
78
78
|
- name: Test
|
|
79
79
|
run: pnpm test
|
|
80
80
|
|
|
81
|
-
- name: Check packaged monorepo creation
|
|
82
|
-
if: ${{ matrix.os == 'ubuntu-latest' && matrix.node-version == 22 }}
|
|
83
|
-
run: pnpm test:packaged-create
|
|
84
|
-
|
|
85
81
|
- name: Upload coverage reports to Codecov
|
|
86
82
|
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
|
87
83
|
env:
|
|
@@ -35,6 +35,10 @@ on:
|
|
|
35
35
|
required: false
|
|
36
36
|
default: false
|
|
37
37
|
type: boolean
|
|
38
|
+
source-sha:
|
|
39
|
+
description: Original main commit to recover (publish modes only)
|
|
40
|
+
required: false
|
|
41
|
+
type: string
|
|
38
42
|
|
|
39
43
|
env:
|
|
40
44
|
HUSKY: 0
|
|
@@ -104,6 +108,7 @@ jobs:
|
|
|
104
108
|
REPO_RELEASE_PACKAGE: ${{ inputs.package }}
|
|
105
109
|
REPO_RELEASE_VERSION: ${{ inputs.version }}
|
|
106
110
|
REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }}
|
|
111
|
+
REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }}
|
|
107
112
|
run: pnpm exec repo release ci
|
|
108
113
|
|
|
109
114
|
- name: Preserve npm publish progress
|
package/assets/package.json
CHANGED
|
@@ -73,25 +73,21 @@
|
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@commitlint/cli": "^21.2.3",
|
|
75
75
|
"@eslint/config-inspector": "^3.5.0",
|
|
76
|
-
"@icebreakers/commitlint-config": "workspace:*",
|
|
77
|
-
"@icebreakers/eslint-config": "workspace:*",
|
|
78
|
-
"@icebreakers/monorepo": "workspace:*",
|
|
79
|
-
"@icebreakers/stylelint-config": "workspace:*",
|
|
80
76
|
"@types/node": "^26.6.3",
|
|
81
|
-
"@vitest/coverage-v8": "~5.0.
|
|
77
|
+
"@vitest/coverage-v8": "~5.0.3",
|
|
82
78
|
"eslint": "^10.11.0",
|
|
83
79
|
"execa": "^10.0.1",
|
|
84
80
|
"husky": "^9.1.7",
|
|
85
81
|
"lint-staged": "^17.6.0",
|
|
86
82
|
"only-allow": "^1.2.2",
|
|
87
|
-
"repoctl": "
|
|
83
|
+
"repoctl": "latest",
|
|
88
84
|
"stylelint": "^17.15.0",
|
|
89
85
|
"tailwindcss": "^4.3.3",
|
|
90
86
|
"tsd": "^0.33.0",
|
|
91
87
|
"tsdown": "0.23.0",
|
|
92
88
|
"turbo": "^2.11.5",
|
|
93
89
|
"typescript": "^6.0.3",
|
|
94
|
-
"vitest": "~5.0.
|
|
90
|
+
"vitest": "~5.0.3",
|
|
95
91
|
"yaml": "^2.9.1"
|
|
96
92
|
},
|
|
97
93
|
"publishConfig": {
|
package/assets/turbo.json
CHANGED
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
".env*",
|
|
18
18
|
"package.json",
|
|
19
19
|
"tsconfig*.json",
|
|
20
|
-
"*.config.{js,ts,mjs,mts}"
|
|
20
|
+
"*.config.{js,ts,mjs,mts}",
|
|
21
|
+
"public/**",
|
|
22
|
+
"nimbus.json"
|
|
21
23
|
],
|
|
22
24
|
"outputs": [
|
|
23
25
|
"dist/**",
|
|
@@ -30,12 +32,14 @@
|
|
|
30
32
|
"^lint"
|
|
31
33
|
],
|
|
32
34
|
"inputs": [
|
|
33
|
-
"**/*.{js,jsx,cjs,mjs,ts,tsx,cts,mts,vue}",
|
|
35
|
+
"**/*.{js,jsx,cjs,mjs,ts,tsx,cts,mts,vue,astro,css,scss,less}",
|
|
34
36
|
"**/*.{json,html,md,mdx,yml,yaml}",
|
|
35
37
|
"*.config.{js,ts,mjs,mts}",
|
|
36
38
|
".eslintrc*",
|
|
37
39
|
".stylelintrc*",
|
|
38
|
-
"package.json"
|
|
40
|
+
"package.json",
|
|
41
|
+
"public/**",
|
|
42
|
+
"nimbus.json"
|
|
39
43
|
],
|
|
40
44
|
"outputs": []
|
|
41
45
|
},
|
|
@@ -88,7 +92,10 @@
|
|
|
88
92
|
".env*",
|
|
89
93
|
"test/**",
|
|
90
94
|
"package.json",
|
|
91
|
-
"tsconfig*.json"
|
|
95
|
+
"tsconfig*.json",
|
|
96
|
+
"public/**",
|
|
97
|
+
"nimbus.json",
|
|
98
|
+
"*.config.{js,ts,mjs,mts}"
|
|
92
99
|
],
|
|
93
100
|
"outputs": []
|
|
94
101
|
},
|
package/dist/cli.mjs
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as isGitignoreFile, c as toWorkspaceGitignorePath, d as packageDir, f as skeletonDir, h as getAssetTargets$1, i as shouldSkipTemplatePath, l as templateChoices$1, m as assetTargets$1, n as sanitizePublishedWorkspaceContent, o as toPublishGitignorePath, p as templatesDir, r as createTemplateCopyFilter, s as toWorkspaceAssetPath, t as prepareAssets, u as assetsDir } from "./prepare-
|
|
1
|
+
import { a as isGitignoreFile, c as toWorkspaceGitignorePath, d as packageDir, f as skeletonDir, h as getAssetTargets$1, i as shouldSkipTemplatePath, l as templateChoices$1, m as assetTargets$1, n as sanitizePublishedWorkspaceContent, o as toPublishGitignorePath, p as templatesDir, r as createTemplateCopyFilter, s as toWorkspaceAssetPath, t as prepareAssets, u as assetsDir } from "./prepare-2VvFwYDz.mjs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import fs, { access, open, readFile, rm } from "node:fs/promises";
|
|
4
4
|
import exec from "nanoexec";
|
|
@@ -42,7 +42,7 @@ async function isPrepared() {
|
|
|
42
42
|
const checks = [
|
|
43
43
|
path.join(assetsDir, "AGENTS.md"),
|
|
44
44
|
path.join(assetsDir, "LICENSE"),
|
|
45
|
-
path.join(templatesDir,
|
|
45
|
+
...templateChoices$1.map((template) => path.join(templatesDir, template.source))
|
|
46
46
|
];
|
|
47
47
|
if (!(await Promise.all(checks.map(pathExists))).every(Boolean)) return false;
|
|
48
48
|
const sourceRoot = path.resolve(packageDir, "..", "..");
|
|
@@ -96,6 +96,14 @@ const templateChoices = [
|
|
|
96
96
|
target: "apps/cli",
|
|
97
97
|
category: "tool",
|
|
98
98
|
description: "TypeScript 命令行工具模板"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
key: "nimbus",
|
|
102
|
+
label: "Nimbus 文档(默认)",
|
|
103
|
+
source: "nimbus",
|
|
104
|
+
target: "apps/docs",
|
|
105
|
+
category: "docs",
|
|
106
|
+
description: "默认文档模板:Nimbus + Astro,中英双语与 AI 文档入口"
|
|
99
107
|
}
|
|
100
108
|
];
|
|
101
109
|
//#endregion
|
|
@@ -144,7 +152,9 @@ const skipDirs = /* @__PURE__ */ new Set([
|
|
|
144
152
|
".vite",
|
|
145
153
|
".tmp",
|
|
146
154
|
".vue-global-types",
|
|
147
|
-
".wrangler"
|
|
155
|
+
".wrangler",
|
|
156
|
+
".astro",
|
|
157
|
+
".nimbus"
|
|
148
158
|
]);
|
|
149
159
|
const skipFiles = /* @__PURE__ */ new Set([
|
|
150
160
|
".DS_Store",
|
|
@@ -171,8 +181,18 @@ function createTemplateCopyFilter(rootDir) {
|
|
|
171
181
|
//#region src/prepare/published.ts
|
|
172
182
|
function sanitizePublishedManifestContent(content) {
|
|
173
183
|
const manifest = JSON.parse(content);
|
|
184
|
+
if (manifest.devDependencies) {
|
|
185
|
+
for (const name of [
|
|
186
|
+
"@icebreakers/commitlint-config",
|
|
187
|
+
"@icebreakers/eslint-config",
|
|
188
|
+
"@icebreakers/monorepo",
|
|
189
|
+
"@icebreakers/stylelint-config",
|
|
190
|
+
"playwright"
|
|
191
|
+
]) delete manifest.devDependencies[name];
|
|
192
|
+
if (manifest.devDependencies["repoctl"]?.startsWith("workspace:")) manifest.devDependencies["repoctl"] = "latest";
|
|
193
|
+
}
|
|
174
194
|
if (manifest.scripts) {
|
|
175
|
-
for (const name of Object.keys(manifest.scripts)) if (name.startsWith("dev:") || name === "test:dev-scenarios" || name === "test:worker-types" || name === "test:packaged-create") delete manifest.scripts[name];
|
|
195
|
+
for (const name of Object.keys(manifest.scripts)) if (name.startsWith("dev:") || name === "test:dev-scenarios" || name === "test:worker-types" || name === "test:packaged-create" || name === "test:packaged-nimbus") delete manifest.scripts[name];
|
|
176
196
|
manifest.scripts["dev"] = "turbo run dev --concurrency=20";
|
|
177
197
|
if (manifest.scripts["test"]) manifest.scripts["test"] = manifest.scripts["test"].replace(" && pnpm test:dev-scenarios", "");
|
|
178
198
|
}
|
|
@@ -360,7 +380,7 @@ async function removeSourceRepoChecks() {
|
|
|
360
380
|
const workflowPath = path$1.join(assetsDir, ".github/workflows/ci.yml");
|
|
361
381
|
if (await pathExists(workflowPath)) {
|
|
362
382
|
const workflow = await fs.readFile(workflowPath, "utf8");
|
|
363
|
-
await fs.writeFile(workflowPath, workflow.replace(/\r?\n\s+- name: Check Worker type generation from packaged templates\r?\n\s+run:
|
|
383
|
+
await fs.writeFile(workflowPath, workflow.replace(/\r?\n\s+- name: (?:Check Worker type generation from packaged templates|Install browser for packaged documentation checks|Check packaged monorepo creation|Check packaged Nimbus documentation)\r?\n(?:\s+if: [^\r\n]+\r?\n)?\s+run: [^\r\n]+\r?\n/g, "\n").replace(/\n{3,}/g, "\n\n"));
|
|
364
384
|
}
|
|
365
385
|
const manifestPath = path$1.join(assetsDir, "package.json");
|
|
366
386
|
if (await pathExists(manifestPath)) {
|
package/package.json
CHANGED
package/template-data.mjs
CHANGED
|
@@ -47,4 +47,12 @@ export const templateChoices = [
|
|
|
47
47
|
category: 'tool',
|
|
48
48
|
description: 'TypeScript 命令行工具模板',
|
|
49
49
|
},
|
|
50
|
+
{
|
|
51
|
+
key: 'nimbus',
|
|
52
|
+
label: 'Nimbus 文档(默认)',
|
|
53
|
+
source: 'nimbus',
|
|
54
|
+
target: 'apps/docs',
|
|
55
|
+
category: 'docs',
|
|
56
|
+
description: '默认文档模板:Nimbus + Astro,中英双语与 AI 文档入口',
|
|
57
|
+
},
|
|
50
58
|
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Documentation workspace
|
|
2
|
+
|
|
3
|
+
This is a static Nimbus + Astro documentation site. Run commands in this workspace; install dependencies from the monorepo root after `corepack enable`.
|
|
4
|
+
|
|
5
|
+
- Content lives in `src/content/docs/`; English uses the root and Chinese uses `zh/` with matching relative filenames. Keep both translations and links in sync. The directory tree supplies routes and navigation.
|
|
6
|
+
- Layouts and components are project-owned. Keep modules small. Put styles in `src/styles/` so Stylelint checks every authored style.
|
|
7
|
+
- Register MDX components in `src/components.ts`. Add a text conversion in `astro.config.ts` when a custom component conveys information that would otherwise disappear from Markdown.
|
|
8
|
+
- Set the canonical `site` URL and project title in `astro.config.ts` before deployment. Static output is `dist/` and can be hosted anywhere.
|
|
9
|
+
- Run `pnpm build`, `pnpm lint`, and `pnpm typecheck`. `typecheck` combines Astro diagnostics with TypeScript checks. Search uses the production Pagefind index; verify it with `pnpm preview` after building.
|
|
10
|
+
- Verify `/llms.txt`, `/zh/llms.txt`, `/llms-full.txt`, and each page's `/index.md` and `/index.mdx`. Keep private content outside public content collections; `noindex` is not access control.
|
|
11
|
+
- `draft: true` excludes unfinished pages from production. When adding a page, create its translation before publishing so the language switch remains valid.
|
|
12
|
+
- Keep `nimbus.json` and `UPSTREAM.md` when upgrading. Review Nimbus migrations and project-owned changes before advancing the reviewed version.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License Copyright (c) 2025 Cloudflare, Inc.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of
|
|
4
|
+
charge, to any person obtaining a copy of this software and associated
|
|
5
|
+
documentation files (the "Software"), to deal in the Software without
|
|
6
|
+
restriction, including without limitation the rights to use, copy, modify, merge,
|
|
7
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice
|
|
12
|
+
(including the next paragraph) shall be included in all copies or substantial
|
|
13
|
+
portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
16
|
+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
18
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
19
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Project docs / 项目文档
|
|
2
|
+
|
|
3
|
+
A small bilingual Nimbus + Astro documentation site. 英文位于 `/`,中文位于 `/zh/`。
|
|
4
|
+
|
|
5
|
+
From the monorepo root, run `corepack enable` and `pnpm install`. Then run these commands in this directory:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm dev
|
|
9
|
+
pnpm build
|
|
10
|
+
pnpm preview
|
|
11
|
+
pnpm lint
|
|
12
|
+
pnpm typecheck
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Edit `src/content/docs/` and its `zh/` translations. Set your project title and canonical site URL in `astro.config.ts` before publishing `dist/` to a static host. Search is available after a production build.
|
|
16
|
+
|
|
17
|
+
机器可读入口包括 `/llms.txt`、`/zh/llms.txt`、`/llms-full.txt`,以及页面的 `/index.md` 和 `/index.mdx`。详见 `AGENTS.md` 和 `UPSTREAM.md`。
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Upstream source
|
|
2
|
+
|
|
3
|
+
This template adapts the static empty starter from [Cloudflare Nimbus](https://github.com/cloudflare/nimbus), released under the MIT license (see `LICENSE`).
|
|
4
|
+
|
|
5
|
+
- Starter tag: `templates-v0.7.9`
|
|
6
|
+
- Starter commit: `aae348048a8c659f84c39696ee6b20c2ad2f5ae2`
|
|
7
|
+
- Nimbus package: `@cloudflare/nimbus-docs@0.15.2`
|
|
8
|
+
- Astro: `7.3.1`
|
|
9
|
+
|
|
10
|
+
Nimbus declares Astro `>=7.2.6 <8`; Astro requires Node `>=22.12.0`, so this workspace retains its stricter Node `>=22.13.0` baseline. Builds, Astro diagnostics and TypeScript checks were verified with the repository's TypeScript `6.0.3` and Vite `8.3.1` constraints. Resolved dependencies are recorded in the monorepo's root `pnpm-lock.yaml`; generated projects use their own root workspace lockfile.
|
|
11
|
+
|
|
12
|
+
Agent endpoint routes and the content-loading approach come from that starter. The bilingual layout, navigation, search interface, examples and workspace checks are repoctl adaptations. These files are maintained locally; generating a project never downloads the upstream starter.
|
|
13
|
+
|
|
14
|
+
The local head component emits page-specific language metadata because the upstream head uses the site-wide locale. Client scripts are emitted as external assets so Astro does not inline them before Vite finalizes Pagefind's dynamic import.
|
|
15
|
+
|
|
16
|
+
The package version and starter tag were checked against published package metadata. `nimbus.json` records the reviewed package API baseline. The original full starter was not copied wholesale, so upstream starter diffs are not a claim that every local file is an unmodified upstream component.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import nimbus, { defineConfig as defineNimbusConfig } from '@cloudflare/nimbus-docs'
|
|
2
|
+
import { defineConfig } from 'astro/config'
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
output: 'static',
|
|
6
|
+
// Keep the Pagefind loader external so Vite finalizes dynamic imports before Astro renders it.
|
|
7
|
+
vite: { build: { assetsInlineLimit: 0 } },
|
|
8
|
+
integrations: [nimbus(defineNimbusConfig({
|
|
9
|
+
// Set your production origin before publishing.
|
|
10
|
+
site: 'https://docs.example.com',
|
|
11
|
+
title: 'Project docs',
|
|
12
|
+
description: 'Guides and examples for your project.',
|
|
13
|
+
locale: 'en',
|
|
14
|
+
github: null,
|
|
15
|
+
}), {
|
|
16
|
+
icons: false,
|
|
17
|
+
rules: {
|
|
18
|
+
'nimbus/frontmatter-shape': 'error',
|
|
19
|
+
'nimbus/internal-link': 'error',
|
|
20
|
+
'nimbus/single-h1': 'error',
|
|
21
|
+
},
|
|
22
|
+
markdown: {
|
|
23
|
+
componentMap: {
|
|
24
|
+
Aside: { revision: '1', render: ({ children }) => children },
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
})],
|
|
28
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import astro from 'eslint-plugin-astro'
|
|
2
|
+
import * as mdx from 'eslint-plugin-mdx'
|
|
3
|
+
import { defineEslintConfig } from 'repoctl/tooling'
|
|
4
|
+
|
|
5
|
+
const shared = await defineEslintConfig({ options: { astro: false, formatters: false } })
|
|
6
|
+
|
|
7
|
+
// Markup has its own parser and formatter. Shared JS rules still check the
|
|
8
|
+
// virtual TypeScript files extracted from Astro script blocks.
|
|
9
|
+
const code = shared.map((config) => {
|
|
10
|
+
if (Object.keys(config).every(key => key === 'name' || key === 'ignores')) {
|
|
11
|
+
return config
|
|
12
|
+
}
|
|
13
|
+
return { ...config, ignores: [...(config.ignores ?? []), '**/*.astro', '**/*.mdx', '**/*.mdx/**'] }
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export default [
|
|
17
|
+
...code,
|
|
18
|
+
...astro.configs['flat/recommended'],
|
|
19
|
+
{
|
|
20
|
+
...mdx.flat,
|
|
21
|
+
files: ['**/*.mdx'],
|
|
22
|
+
languageOptions: { ...mdx.flat.languageOptions, globals: { Aside: 'readonly' } },
|
|
23
|
+
},
|
|
24
|
+
{ ignores: ['.astro/**', '.nimbus/**', 'dist/**', '**/*.css'] },
|
|
25
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@icebreakers/nimbus-template",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"private": true,
|
|
6
|
+
"description": "Bilingual Nimbus documentation starter",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=22.13.0"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "astro dev",
|
|
13
|
+
"build": "pnpm check:locales && astro build",
|
|
14
|
+
"preview": "astro preview",
|
|
15
|
+
"typecheck": "astro check && tsc --noEmit",
|
|
16
|
+
"lint": "eslint . && stylelint \"src/styles/**/*.css\" && nimbus-docs lint",
|
|
17
|
+
"lint:docs": "nimbus-docs lint",
|
|
18
|
+
"lint:docs:fix": "nimbus-docs lint --fix",
|
|
19
|
+
"check:locales": "node scripts/check-locales.mjs"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@cloudflare/nimbus-docs": "0.15.2",
|
|
23
|
+
"astro": "7.3.5"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@astrojs/check": "^0.9.10",
|
|
27
|
+
"@astrojs/language-server": "2.17.1",
|
|
28
|
+
"astro-eslint-parser": "^3.2.0",
|
|
29
|
+
"eslint-plugin-astro": "^3.2.1",
|
|
30
|
+
"eslint-plugin-mdx": "^3.8.1",
|
|
31
|
+
"pagefind": "^1.5.2",
|
|
32
|
+
"typescript": "^6.0.3"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="7" fill="#1d4ed8"/><path d="M9 8h10l4 4v12H9zM18 8v5h5M12 17h8M12 21h6" fill="none" stroke="white" stroke-width="1.6" stroke-linejoin="round"/></svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { readdir } from 'node:fs/promises'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
const content = new URL('../src/content/docs/', import.meta.url)
|
|
6
|
+
const files = await readdir(content, { recursive: true })
|
|
7
|
+
const pages = files.filter(file => /\.mdx?$/.test(file)).map(file => file.split(path.sep).join('/'))
|
|
8
|
+
const english = pages.filter(file => !file.startsWith('zh/')).sort()
|
|
9
|
+
const chinese = pages.filter(file => file.startsWith('zh/')).map(file => file.slice(3)).sort()
|
|
10
|
+
assert.deepEqual(chinese, english, 'Every published page needs matching English and Chinese source files.')
|
|
11
|
+
console.log(`Locale parity checked: ${english.length} page pairs.`)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { withBase } from '@cloudflare/nimbus-docs/runtime'
|
|
3
|
+
import { config } from 'virtual:nimbus/config'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
title: string
|
|
7
|
+
description?: string | undefined
|
|
8
|
+
markdownUrl?: string | undefined
|
|
9
|
+
noindex?: boolean | undefined
|
|
10
|
+
chinese: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { title, description = config.description, markdownUrl, noindex, chinese } = Astro.props
|
|
14
|
+
const base = import.meta.env.BASE_URL
|
|
15
|
+
const fullTitle = `${title} | ${config.title}`
|
|
16
|
+
const language = chinese ? 'zh-CN' : 'en'
|
|
17
|
+
const canonical = new URL(Astro.url.pathname, Astro.site)
|
|
18
|
+
const structuredData = JSON.stringify({
|
|
19
|
+
'@context': 'https://schema.org',
|
|
20
|
+
'@type': 'WebPage',
|
|
21
|
+
'name': fullTitle,
|
|
22
|
+
description,
|
|
23
|
+
'url': canonical.href,
|
|
24
|
+
'inLanguage': language,
|
|
25
|
+
})
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
<title>{fullTitle}</title>
|
|
29
|
+
<meta name="generator" content={Astro.generator} />
|
|
30
|
+
<meta name="description" content={description} />
|
|
31
|
+
{noindex && <meta name="robots" content="noindex" />}
|
|
32
|
+
<link rel="icon" type="image/svg+xml" href={withBase('/favicon.svg', base)} />
|
|
33
|
+
<link rel="stylesheet" href={withBase('/_nimbus/shiki.css', base)} />
|
|
34
|
+
<link rel="canonical" href={canonical} />
|
|
35
|
+
<link rel="sitemap" href={withBase('/sitemap-index.xml', base)} />
|
|
36
|
+
{markdownUrl && <link rel="alternate" type="text/markdown" href={new URL(withBase(markdownUrl, base), Astro.site)} />}
|
|
37
|
+
<meta property="og:title" content={fullTitle} />
|
|
38
|
+
<meta property="og:type" content="article" />
|
|
39
|
+
<meta property="og:site_name" content={config.title} />
|
|
40
|
+
<meta property="og:locale" content={chinese ? 'zh_CN' : 'en_US'} />
|
|
41
|
+
<meta property="og:description" content={description} />
|
|
42
|
+
<meta property="og:url" content={canonical} />
|
|
43
|
+
<script type="application/ld+json" set:html={structuredData} />
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
interface SearchResult {
|
|
2
|
+
url: string
|
|
3
|
+
meta: { title?: string }
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface Pagefind {
|
|
7
|
+
init: () => Promise<void>
|
|
8
|
+
search: (query: string) => Promise<{ results: { data: () => Promise<SearchResult> }[] }>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Pagefind is emitted by the Nimbus production build, not bundled by Vite.
|
|
12
|
+
export function mountSearch(root: HTMLElement) {
|
|
13
|
+
const form = root.querySelector('form')!
|
|
14
|
+
const input = root.querySelector('input')!
|
|
15
|
+
const status = root.querySelector<HTMLElement>('[role="status"]')!
|
|
16
|
+
const results = root.querySelector('ul')!
|
|
17
|
+
let api: Promise<Pagefind> | undefined
|
|
18
|
+
let request = 0
|
|
19
|
+
|
|
20
|
+
form.addEventListener('submit', async (event) => {
|
|
21
|
+
event.preventDefault()
|
|
22
|
+
const current = ++request
|
|
23
|
+
results.replaceChildren()
|
|
24
|
+
const query = input.value.trim()
|
|
25
|
+
if (!query) {
|
|
26
|
+
status.textContent = ''
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
status.textContent = root.dataset.loading ?? ''
|
|
30
|
+
try {
|
|
31
|
+
const base = (root.dataset.base ?? '/').replace(/\/$/, '')
|
|
32
|
+
api ??= import(/* @vite-ignore */ `${base}/pagefind/pagefind.js`).then(async (module: Pagefind) => {
|
|
33
|
+
await module.init()
|
|
34
|
+
return module
|
|
35
|
+
})
|
|
36
|
+
const response = await (await api).search(query)
|
|
37
|
+
const pages = await Promise.all(response.results.slice(0, 10).map(result => result.data()))
|
|
38
|
+
if (current !== request) {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
status.textContent = pages.length ? '' : root.dataset.empty ?? ''
|
|
42
|
+
for (const page of pages) {
|
|
43
|
+
const url = new URL(page.url, window.location.origin)
|
|
44
|
+
if (url.origin !== window.location.origin) {
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
const item = document.createElement('li')
|
|
48
|
+
const link = document.createElement('a')
|
|
49
|
+
link.href = url.href
|
|
50
|
+
link.textContent = page.meta.title ?? page.url
|
|
51
|
+
item.append(link)
|
|
52
|
+
results.append(item)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
api = undefined
|
|
57
|
+
if (current === request) {
|
|
58
|
+
status.textContent = root.dataset.unavailable ?? ''
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { labels } from '../../lib/locale'
|
|
3
|
+
|
|
4
|
+
interface Props { chinese: boolean }
|
|
5
|
+
const { chinese } = Astro.props
|
|
6
|
+
const text = labels[chinese ? 'zh' : 'en']
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<details class="search-panel" data-search data-base={import.meta.env.BASE_URL} data-loading={text.loading} data-empty={text.empty} data-unavailable={text.unavailable}>
|
|
10
|
+
<summary>{text.search}</summary>
|
|
11
|
+
<form role="search">
|
|
12
|
+
<label for="docs-search">{text.search}</label>
|
|
13
|
+
<div class="search-controls">
|
|
14
|
+
<input id="docs-search" name="query" type="search" required autocomplete="off" />
|
|
15
|
+
<button type="submit">{text.submit}</button>
|
|
16
|
+
</div>
|
|
17
|
+
</form>
|
|
18
|
+
<p role="status" aria-live="polite"></p>
|
|
19
|
+
<ul class="search-results"></ul>
|
|
20
|
+
</details>
|
|
21
|
+
|
|
22
|
+
<script>
|
|
23
|
+
import { mountSearch } from './client'
|
|
24
|
+
|
|
25
|
+
document.querySelectorAll<HTMLElement>('[data-search]').forEach(mountSearch)
|
|
26
|
+
</script>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { SidebarItem } from '@cloudflare/nimbus-docs/types'
|
|
3
|
+
import { withBase } from '@cloudflare/nimbus-docs/runtime'
|
|
4
|
+
|
|
5
|
+
interface Props { items: SidebarItem[] }
|
|
6
|
+
const { items } = Astro.props
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<ul class="navigation-list">
|
|
10
|
+
{items.map(item => (
|
|
11
|
+
<li>
|
|
12
|
+
{item.type === 'group'
|
|
13
|
+
? (
|
|
14
|
+
<>
|
|
15
|
+
{item.indexHref
|
|
16
|
+
? <a href={withBase(item.indexHref, import.meta.env.BASE_URL)} aria-current={item.indexIsCurrent ? 'page' : undefined}>{item.label}</a>
|
|
17
|
+
: <span>{item.label}</span>}
|
|
18
|
+
<Astro.self items={item.children} />
|
|
19
|
+
</>
|
|
20
|
+
)
|
|
21
|
+
: (
|
|
22
|
+
<a href={withBase(item.href, import.meta.env.BASE_URL)} aria-current={item.type === 'link' && item.isCurrent ? 'page' : undefined}>{item.label}</a>
|
|
23
|
+
)}
|
|
24
|
+
</li>
|
|
25
|
+
))}
|
|
26
|
+
</ul>
|