@karaoke-cms/create 0.9.2 → 0.9.5
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 +46 -40
- package/karaoke-create-vault/.obsidian/workspace.json +6 -20
- package/karaoke-create-vault/docs/getting-started.md +31 -0
- package/package.json +5 -5
- package/src/index.js +32 -23
- package/src/templates.js +11 -15
- package/karaoke-create-vault/karaoke-cms/config/collections.yaml +0 -10
- package/karaoke-create-vault/karaoke-cms/config/index.md +0 -14
- package/karaoke-create-vault/karaoke-cms/config/menus.yaml +0 -58
- package/karaoke-create-vault/karaoke-cms/manual/configuration.md +0 -77
- package/karaoke-create-vault/karaoke-cms/manual/content.md +0 -38
- package/karaoke-create-vault/karaoke-cms/manual/deployment.md +0 -46
- package/karaoke-create-vault/karaoke-cms/manual/index.md +0 -41
- package/karaoke-create-vault/karaoke-cms/manual/privacy.md +0 -37
- package/karaoke-create-vault/karaoke-cms/templates/blog-header.md +0 -9
- package/karaoke-create-vault/karaoke-cms/templates/docs-header.md +0 -9
- package/karaoke-create-vault/karaoke-cms/templates/index-by-foldernote.md +0 -8
- package/karaoke-create-vault/karaoke-cms/templates/index.md +0 -15
package/README.md
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# @karaoke-cms/create
|
|
2
2
|
|
|
3
|
-
Scaffolding tool for karaoke-cms. Creates a complete new project from scratch with a single command.
|
|
3
|
+
Scaffolding tool for karaoke-cms. Creates a complete new project from scratch with a single command, then optionally deploys a live preview to Cloudflare Pages.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
`packages/create/` in the monorepo. Published to npm as `@karaoke-cms/create` and invoked via npm's `create` shorthand:
|
|
5
|
+
## Usage
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
8
|
npm create @karaoke-cms@latest
|
|
@@ -12,37 +10,26 @@ npm create @karaoke-cms@latest
|
|
|
12
10
|
npm create @karaoke-cms@latest my-site
|
|
13
11
|
```
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
## What it does
|
|
13
|
+
The wizard asks for your project name, site title, URL, and description, then generates everything and installs dependencies.
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
At the end you're offered a one-step deploy to Cloudflare Pages (defaults to **yes** — your site can be live before you open your code editor).
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
1. Project directory name
|
|
23
|
-
2. Site title
|
|
24
|
-
3. Site URL (for sitemap and OG tags)
|
|
25
|
-
4. Description
|
|
26
|
-
5. Theme (`default`, `minimal`, or `blog`)
|
|
27
|
-
6. Enable Pagefind search? (y/n)
|
|
28
|
-
7. Enable Giscus comments? (y/n) — if yes, prompts for repo, repoId, category, categoryId
|
|
17
|
+
## What gets created
|
|
29
18
|
|
|
30
|
-
**Generated files:**
|
|
31
19
|
```
|
|
32
20
|
my-site/
|
|
33
|
-
package.json
|
|
34
|
-
astro.config.mjs
|
|
35
|
-
karaoke.config.ts
|
|
21
|
+
package.json # @karaoke-cms/* deps pinned to current version
|
|
22
|
+
astro.config.mjs # karaoke() integration, site URL
|
|
23
|
+
karaoke.config.ts # title, description, theme, blog module
|
|
36
24
|
src/
|
|
37
|
-
content.config.ts
|
|
38
|
-
env.d.ts
|
|
25
|
+
content.config.ts # makeCollections() wired to vault/
|
|
26
|
+
env.d.ts # TypeScript types for virtual:karaoke-cms/config
|
|
39
27
|
tsconfig.json
|
|
40
28
|
.gitignore
|
|
41
|
-
.env.default
|
|
42
|
-
public/
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
blog/
|
|
29
|
+
.env.default # KARAOKE_VAULT=./vault/
|
|
30
|
+
public/_redirects # Cloudflare Pages 404 config
|
|
31
|
+
vault/ # Obsidian vault with sample blog posts
|
|
32
|
+
blog/ # 30 demo posts (publish: true)
|
|
46
33
|
docs/
|
|
47
34
|
karaoke-cms/
|
|
48
35
|
config/
|
|
@@ -50,27 +37,46 @@ my-site/
|
|
|
50
37
|
menus.yaml
|
|
51
38
|
```
|
|
52
39
|
|
|
53
|
-
|
|
40
|
+
A git repository is initialised with an initial commit. Opening `vault/` in Obsidian lets you write content immediately.
|
|
54
41
|
|
|
55
|
-
##
|
|
42
|
+
## Generated karaoke.config.ts
|
|
56
43
|
|
|
57
|
-
```
|
|
58
|
-
|
|
44
|
+
```ts
|
|
45
|
+
import { defineConfig } from '@karaoke-cms/astro';
|
|
46
|
+
import { blog } from '@karaoke-cms/module-blog';
|
|
47
|
+
import { themeDefault } from '@karaoke-cms/theme-default';
|
|
48
|
+
import { loadEnv } from '@karaoke-cms/astro/env';
|
|
49
|
+
|
|
50
|
+
const env = loadEnv(new URL('.', import.meta.url));
|
|
59
51
|
|
|
52
|
+
export default defineConfig({
|
|
53
|
+
vault: env.KARAOKE_VAULT,
|
|
54
|
+
title: 'My Site',
|
|
55
|
+
description: 'What this site is about.',
|
|
56
|
+
modules: [blog({ mount: '/blog' })],
|
|
57
|
+
theme: themeDefault(),
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Local dev
|
|
62
|
+
|
|
63
|
+
```bash
|
|
60
64
|
cd my-site
|
|
61
|
-
npm install
|
|
62
65
|
npm run dev # → http://localhost:4321
|
|
63
66
|
```
|
|
64
67
|
|
|
65
|
-
|
|
68
|
+
## Deploy
|
|
66
69
|
|
|
67
|
-
|
|
70
|
+
```bash
|
|
71
|
+
npm run deploy # publishes to Cloudflare Pages
|
|
72
|
+
```
|
|
68
73
|
|
|
69
|
-
|
|
74
|
+
Requires a Cloudflare account and the `wrangler` CLI. The wizard handles the first deploy interactively.
|
|
70
75
|
|
|
71
|
-
|
|
76
|
+
## What's new in 0.9.5
|
|
72
77
|
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
78
|
+
- **Deploy defaults to yes** — the Cloudflare Pages deploy prompt now defaults to YES, so new sites are live by the end of the wizard
|
|
79
|
+
- **Three success screens** — distinct output for deploy success, declined, and failed (failed surfaces the error and next steps)
|
|
80
|
+
- **isTTY color guard** — ANSI color codes are disabled in CI and piped output
|
|
81
|
+
- **30 demo blog posts** included in the scaffolded vault so the site is populated on first visit
|
|
82
|
+
- **Generated `karaoke.config.ts`** uses `themeDefault()` + `blog()` module API (replaces the old string-based theme config)
|
|
@@ -20,23 +20,8 @@
|
|
|
20
20
|
"icon": "lucide-file",
|
|
21
21
|
"title": "getting-started"
|
|
22
22
|
}
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"id": "52e565c48d7a7c39",
|
|
26
|
-
"type": "leaf",
|
|
27
|
-
"state": {
|
|
28
|
-
"type": "markdown",
|
|
29
|
-
"state": {
|
|
30
|
-
"file": "karaoke-cms/manual/configuration.md",
|
|
31
|
-
"mode": "source",
|
|
32
|
-
"source": false
|
|
33
|
-
},
|
|
34
|
-
"icon": "lucide-file",
|
|
35
|
-
"title": "configuration"
|
|
36
|
-
}
|
|
37
23
|
}
|
|
38
|
-
]
|
|
39
|
-
"currentTab": 1
|
|
24
|
+
]
|
|
40
25
|
}
|
|
41
26
|
],
|
|
42
27
|
"direction": "vertical"
|
|
@@ -183,10 +168,10 @@
|
|
|
183
168
|
"state": {
|
|
184
169
|
"type": "file-properties",
|
|
185
170
|
"state": {
|
|
186
|
-
"file": "
|
|
171
|
+
"file": "docs/getting-started.md"
|
|
187
172
|
},
|
|
188
173
|
"icon": "lucide-info",
|
|
189
|
-
"title": "File properties for
|
|
174
|
+
"title": "File properties for getting-started"
|
|
190
175
|
}
|
|
191
176
|
}
|
|
192
177
|
],
|
|
@@ -208,15 +193,16 @@
|
|
|
208
193
|
"templater-obsidian:Templater": false
|
|
209
194
|
}
|
|
210
195
|
},
|
|
211
|
-
"active": "
|
|
196
|
+
"active": "d663da17c7b12a45",
|
|
212
197
|
"lastOpenFiles": [
|
|
198
|
+
"karaoke-cms/manual/deployment.md",
|
|
199
|
+
"karaoke-cms/manual/configuration.md",
|
|
213
200
|
"karaoke-cms/templates/index.md",
|
|
214
201
|
"karaoke-cms/config/index.md",
|
|
215
202
|
"karaoke-cms/templates/docs-header.md",
|
|
216
203
|
"karaoke-cms/templates/blog-header.md",
|
|
217
204
|
"karaoke-cms/templates/index-by-foldernote.md",
|
|
218
205
|
"karaoke-cms/manual/content.md",
|
|
219
|
-
"karaoke-cms/manual/configuration.md",
|
|
220
206
|
"blog/hello-world.md",
|
|
221
207
|
"karaoke-cms/templates",
|
|
222
208
|
"karaoke-cms/index.md",
|
|
@@ -5,6 +5,37 @@ date: 2026-01-01
|
|
|
5
5
|
description: "How to set up and use your karaoke-cms site."
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
## System setup
|
|
9
|
+
|
|
10
|
+
**Prerequisites:** Node.js 20+, npm, Obsidian.
|
|
11
|
+
|
|
12
|
+
Create a new project:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm create @karaoke-cms@latest my-site
|
|
16
|
+
cd my-site
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Open the project folder in Obsidian as a vault. Configure `karaoke.config.ts`:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
export default {
|
|
23
|
+
title: "My Site",
|
|
24
|
+
description: "What this site is about.",
|
|
25
|
+
vault: "./karaoke-template-vault/",
|
|
26
|
+
theme: "@karaoke-cms/theme-default",
|
|
27
|
+
};
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Add two secrets to your GitHub repository for deployment:
|
|
31
|
+
|
|
32
|
+
| Secret | Where to get it |
|
|
33
|
+
|--------|-----------------|
|
|
34
|
+
| `CLOUDFLARE_API_TOKEN` | Cloudflare dashboard → API Tokens |
|
|
35
|
+
| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare dashboard → Account overview |
|
|
36
|
+
|
|
37
|
+
Push to `main` — GitHub Actions builds and deploys to Cloudflare Pages automatically.
|
|
38
|
+
|
|
8
39
|
## Open in Obsidian
|
|
9
40
|
|
|
10
41
|
Your project root is an Obsidian vault. Open this folder in Obsidian to write content with full wikilink navigation, templates, and graph view.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karaoke-cms/create",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.5",
|
|
5
5
|
"description": "Scaffold a new karaoke-cms project",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-karaoke-cms": "./src/index.js"
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"scaffold",
|
|
21
21
|
"obsidian"
|
|
22
22
|
],
|
|
23
|
-
"devDependencies": {
|
|
24
|
-
"vitest": "^4.1.1"
|
|
25
|
-
},
|
|
26
23
|
"scripts": {
|
|
27
24
|
"test": "vitest run test/templates.test.js test/index.test.js"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"vitest": "^4.1.1"
|
|
28
28
|
}
|
|
29
|
-
}
|
|
29
|
+
}
|
package/src/index.js
CHANGED
|
@@ -17,12 +17,13 @@ import {
|
|
|
17
17
|
} from './templates.js';
|
|
18
18
|
|
|
19
19
|
// ── ANSI helpers ─────────────────────────────────────────────────────────────
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
20
|
+
const NO_COLOR = !process.stdout.isTTY;
|
|
21
|
+
const R = NO_COLOR ? '' : '\x1b[0m';
|
|
22
|
+
const BOLD = NO_COLOR ? '' : '\x1b[1m';
|
|
23
|
+
const GREEN = NO_COLOR ? '' : '\x1b[32m';
|
|
24
|
+
const CYAN = NO_COLOR ? '' : '\x1b[36m';
|
|
25
|
+
const GRAY = NO_COLOR ? '' : '\x1b[90m';
|
|
26
|
+
const RED = NO_COLOR ? '' : '\x1b[31m';
|
|
26
27
|
|
|
27
28
|
// Use create package's own version as the @karaoke-cms/astro dep range
|
|
28
29
|
// (packages ship in lockstep)
|
|
@@ -110,9 +111,7 @@ async function main() {
|
|
|
110
111
|
const title = await ask('Site title', defaultTitle);
|
|
111
112
|
const description = await ask('Description', 'Our team knowledge base.');
|
|
112
113
|
const themeChoice = await askChoice('Theme', ['default', 'minimal', 'blog'], 0);
|
|
113
|
-
const theme = themeChoice
|
|
114
|
-
? themeChoice
|
|
115
|
-
: `@karaoke-cms/theme-${themeChoice}`;
|
|
114
|
+
const theme = `@karaoke-cms/theme-${themeChoice}`;
|
|
116
115
|
const search = await askYesNo('Enable search? (Pagefind)', true);
|
|
117
116
|
const commentsEnabled = await askYesNo('Enable comments? (requires Giscus setup)', false);
|
|
118
117
|
|
|
@@ -176,34 +175,40 @@ async function main() {
|
|
|
176
175
|
}
|
|
177
176
|
|
|
178
177
|
// ── npm install ──────────────────────────────────────────────────────────────
|
|
179
|
-
console.log(`\n Installing dependencies
|
|
178
|
+
console.log(`\n Installing dependencies... ${GRAY}(this may take a minute)${R}\n`);
|
|
180
179
|
const installResult = spawnSync('npm', ['install'], { cwd: targetDir, stdio: 'inherit' });
|
|
181
180
|
if (installResult.status !== 0) {
|
|
182
181
|
console.log(` ${GRAY}(install failed — run npm install manually)${R}`);
|
|
183
182
|
}
|
|
184
183
|
|
|
185
184
|
// ── Deploy prompt ────────────────────────────────────────────────────────────
|
|
186
|
-
const deployNow = await askYesNo('Publish a live preview to Cloudflare Pages now?',
|
|
187
|
-
|
|
188
|
-
rl.close();
|
|
185
|
+
const deployNow = await askYesNo('Publish a live preview to Cloudflare Pages now?', true);
|
|
189
186
|
|
|
190
187
|
let liveUrl = null;
|
|
188
|
+
let deployFailed = false;
|
|
191
189
|
if (deployNow) {
|
|
192
190
|
const projectName = `${slugify(dir)}-preview`;
|
|
193
191
|
liveUrl = await deployToCloudflare(targetDir, projectName);
|
|
192
|
+
if (!liveUrl) deployFailed = true;
|
|
194
193
|
}
|
|
195
194
|
|
|
195
|
+
rl.close();
|
|
196
|
+
|
|
196
197
|
// ── Success screen ───────────────────────────────────────────────────────────
|
|
197
|
-
|
|
198
|
+
const failNote = deployFailed ? ` ${GRAY}(deploy failed — see above)${R}` : '';
|
|
199
|
+
console.log(`\n${GREEN}✓${R} Done! Created ${BOLD}${dir}/${R}${failNote}\n`);
|
|
198
200
|
if (liveUrl) {
|
|
199
|
-
console.log(` ${BOLD}🎤 Live:${R}
|
|
200
|
-
console.log(` ${BOLD}💻
|
|
201
|
+
console.log(` ${BOLD}🎤 Live URL:${R} ${GREEN}${liveUrl}${R}`);
|
|
202
|
+
console.log(` ${BOLD}💻 Local dev:${R} ${CYAN}cd ${dir} && npm run dev${R}`);
|
|
201
203
|
console.log(` ${BOLD}🔄 Redeploy:${R} ${CYAN}npm run deploy${R}\n`);
|
|
204
|
+
} else if (deployFailed) {
|
|
205
|
+
console.log(` The project is ready. Fix the error above, then:`);
|
|
206
|
+
console.log(` ${CYAN}cd ${dir}${R}`);
|
|
207
|
+
console.log(` ${CYAN}npm run deploy${R} ${GRAY}→ retry publishing to Cloudflare Pages${R}\n`);
|
|
202
208
|
} else {
|
|
203
|
-
console.log(` Next steps:\n`);
|
|
204
209
|
console.log(` ${CYAN}cd ${dir}${R}`);
|
|
205
|
-
console.log(` ${CYAN}npm run dev${R} ${GRAY}→
|
|
206
|
-
console.log(` ${CYAN}npm run deploy${R} ${GRAY}→ publish to Cloudflare Pages${R}\n`);
|
|
210
|
+
console.log(` ${CYAN}npm run dev${R} ${GRAY}→ start local dev server${R}`);
|
|
211
|
+
console.log(` ${CYAN}npm run deploy${R} ${GRAY}→ publish to Cloudflare Pages when ready${R}\n`);
|
|
207
212
|
}
|
|
208
213
|
console.log(` ${GRAY}Open ${BOLD}${dir}/vault/${R}${GRAY} in Obsidian to write content.${R}\n`);
|
|
209
214
|
}
|
|
@@ -232,7 +237,7 @@ export async function deployToCloudflare(targetDir, projectName) {
|
|
|
232
237
|
}
|
|
233
238
|
|
|
234
239
|
// 2. Build
|
|
235
|
-
console.log(` ${CYAN}Building
|
|
240
|
+
console.log(` ${CYAN}Building... ${GRAY}(15–30 seconds)${R}`);
|
|
236
241
|
const build = spawnSync('npm', ['run', 'build'],
|
|
237
242
|
{ cwd: targetDir, stdio: 'inherit' });
|
|
238
243
|
if (build.status !== 0) {
|
|
@@ -263,9 +268,13 @@ export async function deployToCloudflare(targetDir, projectName) {
|
|
|
263
268
|
const liveUrl = `https://${projectName}.pages.dev`;
|
|
264
269
|
|
|
265
270
|
// 6. Write real URL back to astro.config.mjs (replaces placeholder set during scaffold)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
271
|
+
try {
|
|
272
|
+
const configPath = join(targetDir, 'astro.config.mjs');
|
|
273
|
+
const configSrc = readFileSync(configPath, 'utf8');
|
|
274
|
+
writeFileSync(configPath, configSrc.replace('https://your-site.pages.dev', liveUrl));
|
|
275
|
+
} catch {
|
|
276
|
+
console.log(` ${GRAY}Could not update site URL — edit astro.config.mjs manually.${R}`);
|
|
277
|
+
}
|
|
269
278
|
|
|
270
279
|
return liveUrl;
|
|
271
280
|
}
|
package/src/templates.js
CHANGED
|
@@ -43,7 +43,7 @@ export function packageJson({ name, astroVersion, theme }) {
|
|
|
43
43
|
},
|
|
44
44
|
dependencies,
|
|
45
45
|
devDependencies: {
|
|
46
|
-
wrangler: '^
|
|
46
|
+
wrangler: '^4',
|
|
47
47
|
},
|
|
48
48
|
}, null, 2) + '\n';
|
|
49
49
|
}
|
|
@@ -75,32 +75,28 @@ export default defineConfig({
|
|
|
75
75
|
* title: string,
|
|
76
76
|
* description: string,
|
|
77
77
|
* theme: string,
|
|
78
|
-
* search: boolean,
|
|
79
78
|
* comments: { repo: string, repoId: string, category: string, categoryId: string } | null,
|
|
80
79
|
* }} opts
|
|
81
80
|
*/
|
|
82
|
-
export function karaokeConfig({ title, description, theme,
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
if (comments) modules.comments = { enabled: true, ...comments };
|
|
86
|
-
|
|
87
|
-
const modulesStr = Object.keys(modules).length > 0
|
|
88
|
-
? `\n modules: ${JSON.stringify(modules, null, 2).replace(/\n/g, '\n ')},`
|
|
81
|
+
export function karaokeConfig({ title, description, theme, comments }) {
|
|
82
|
+
const commentsStr = comments
|
|
83
|
+
? `\n comments: ${JSON.stringify({ enabled: true, ...comments }, null, 2).replace(/\n/g, '\n ')},`
|
|
89
84
|
: '';
|
|
90
85
|
|
|
91
|
-
return `import
|
|
86
|
+
return `import { defineConfig } from '@karaoke-cms/astro';
|
|
87
|
+
import { blog } from '@karaoke-cms/module-blog';
|
|
88
|
+
import { themeDefault } from '@karaoke-cms/theme-default';
|
|
92
89
|
import { loadEnv } from '@karaoke-cms/astro/env';
|
|
93
90
|
|
|
94
91
|
const env = loadEnv(new URL('.', import.meta.url));
|
|
95
92
|
|
|
96
|
-
|
|
93
|
+
export default defineConfig({
|
|
97
94
|
vault: env.KARAOKE_VAULT,
|
|
98
95
|
title: ${JSON.stringify(title)},
|
|
99
96
|
description: ${JSON.stringify(description)},
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export default config;
|
|
97
|
+
modules: [blog({ mount: '/blog' })],
|
|
98
|
+
theme: themeDefault(),${commentsStr}
|
|
99
|
+
});
|
|
104
100
|
`;
|
|
105
101
|
}
|
|
106
102
|
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Config"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Config
|
|
6
|
-
|
|
7
|
-
Configuration files for your karaoke-cms vault.
|
|
8
|
-
|
|
9
|
-
| File | Purpose |
|
|
10
|
-
|------|---------|
|
|
11
|
-
| `collections.yaml` | Which collections are visible in dev vs production |
|
|
12
|
-
| `menus.yaml` | Site navigation: header menu, footer columns, and their entries |
|
|
13
|
-
|
|
14
|
-
Edit these files to change what appears on your site and in the navigation. Changes take effect on the next dev server restart or build.
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# menus.yaml — define named menus for your site.
|
|
2
|
-
#
|
|
3
|
-
# Each menu has an orientation (horizontal or vertical) and a list of entries.
|
|
4
|
-
# Entries are sorted by weight (ascending). Submenus are defined by nesting entries.
|
|
5
|
-
#
|
|
6
|
-
# when: collection:name — hide entry when the collection is disabled or has no
|
|
7
|
-
# published posts. Omit `when` to always show.
|
|
8
|
-
#
|
|
9
|
-
# If this file is absent, karaoke-cms generates a default main menu (Blog/Docs/Tags)
|
|
10
|
-
# and a default footer menu (RSS) from your active collections.
|
|
11
|
-
|
|
12
|
-
menus:
|
|
13
|
-
main:
|
|
14
|
-
orientation: horizontal
|
|
15
|
-
entries:
|
|
16
|
-
- text: Blog
|
|
17
|
-
href: /blog
|
|
18
|
-
weight: 10
|
|
19
|
-
when: collection:blog
|
|
20
|
-
- text: Docs
|
|
21
|
-
href: /docs
|
|
22
|
-
weight: 20
|
|
23
|
-
when: collection:docs
|
|
24
|
-
- text: Tags
|
|
25
|
-
href: /tags
|
|
26
|
-
weight: 30
|
|
27
|
-
- text: karaoke-cms
|
|
28
|
-
href: /karaoke-cms
|
|
29
|
-
weight: 40
|
|
30
|
-
when: collection:karaoke-cms
|
|
31
|
-
|
|
32
|
-
footer-2:
|
|
33
|
-
orientation: vertical
|
|
34
|
-
entries:
|
|
35
|
-
- text: karaoke-cms
|
|
36
|
-
href: /karaoke-cms/manual/index
|
|
37
|
-
weight: 10
|
|
38
|
-
when: collection:karaoke-cms
|
|
39
|
-
entries:
|
|
40
|
-
- text: Manual
|
|
41
|
-
href: /karaoke-cms/manual/index
|
|
42
|
-
weight: 10
|
|
43
|
-
when: collection:karaoke-cms
|
|
44
|
-
- text: Config
|
|
45
|
-
href: /karaoke-cms/config/index
|
|
46
|
-
weight: 20
|
|
47
|
-
when: collection:karaoke-cms
|
|
48
|
-
- text: Templates
|
|
49
|
-
href: /karaoke-cms/templates/index
|
|
50
|
-
weight: 30
|
|
51
|
-
when: collection:karaoke-cms
|
|
52
|
-
|
|
53
|
-
footer:
|
|
54
|
-
orientation: vertical
|
|
55
|
-
entries:
|
|
56
|
-
- text: RSS
|
|
57
|
-
href: /rss.xml
|
|
58
|
-
weight: 10
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Configuration"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Configuration
|
|
6
|
-
|
|
7
|
-
> **Handbook — dev only.**
|
|
8
|
-
|
|
9
|
-
## karaoke.config.ts
|
|
10
|
-
|
|
11
|
-
The main config file at your project root. TypeScript — fully typed.
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import type { KaraokeConfig } from '@karaoke-cms/astro';
|
|
15
|
-
|
|
16
|
-
const config: KaraokeConfig = {
|
|
17
|
-
title: "My Site",
|
|
18
|
-
description: "What this site is about.",
|
|
19
|
-
theme: "default", // "default" | "minimal"
|
|
20
|
-
modules: {
|
|
21
|
-
search: {
|
|
22
|
-
enabled: true, // Pagefind full-text search
|
|
23
|
-
},
|
|
24
|
-
comments: {
|
|
25
|
-
enabled: true, // Giscus (GitHub Discussions)
|
|
26
|
-
repo: "owner/repo",
|
|
27
|
-
repoId: "R_...",
|
|
28
|
-
category: "General",
|
|
29
|
-
categoryId: "DIC_...",
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export default config;
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Get Giscus values from [giscus.app](https://giscus.app) after enabling Discussions on your repo.
|
|
38
|
-
|
|
39
|
-
## collections.yaml
|
|
40
|
-
|
|
41
|
-
`content/karaoke-cms/config/collections.yaml` controls which collections are visible in dev vs prod:
|
|
42
|
-
|
|
43
|
-
```yaml
|
|
44
|
-
collections:
|
|
45
|
-
blog:
|
|
46
|
-
modes: [dev, prod] # visible in both dev and production
|
|
47
|
-
label: Blog
|
|
48
|
-
docs:
|
|
49
|
-
modes: [dev, prod]
|
|
50
|
-
label: Docs
|
|
51
|
-
karaoke-cms:
|
|
52
|
-
modes: [dev] # dev-only — never ships
|
|
53
|
-
label: Handbook
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
To add a custom collection (e.g., `content/notes/`):
|
|
57
|
-
|
|
58
|
-
```yaml
|
|
59
|
-
collections:
|
|
60
|
-
notes:
|
|
61
|
-
modes: [dev, prod]
|
|
62
|
-
label: Notes
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Layout regions
|
|
66
|
-
|
|
67
|
-
Place UI components in the sidebar or header via `karaoke.config.ts`:
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
layout: {
|
|
71
|
-
regions: {
|
|
72
|
-
right: { components: ['recent-posts'] },
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Available components: `header`, `main-menu`, `search`, `recent-posts`, `footer`.
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Writing Content"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Writing Content
|
|
6
|
-
|
|
7
|
-
> **Handbook — dev only.**
|
|
8
|
-
|
|
9
|
-
## Frontmatter fields
|
|
10
|
-
|
|
11
|
-
```yaml
|
|
12
|
-
---
|
|
13
|
-
title: "My Post" # required — build fails without it
|
|
14
|
-
publish: true # required to appear on site (default: false)
|
|
15
|
-
date: 2026-01-15 # optional — YYYY-MM-DD, used for sorting
|
|
16
|
-
author: "Name" # optional — string or array ["Alice", "Bob"]
|
|
17
|
-
description: "..." # optional — used in OG meta tags and RSS
|
|
18
|
-
tags: [writing, tutorial] # optional — enables tag pages at /tags/[tag]
|
|
19
|
-
---
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Privacy model
|
|
23
|
-
|
|
24
|
-
Every file is **private by default**. `publish: false` (or a missing `publish` field) means the file stays in your vault and never enters the build — not in HTML, not in RSS, not in the sitemap, not in the Pagefind search index.
|
|
25
|
-
|
|
26
|
-
Only `publish: true` files appear on your site.
|
|
27
|
-
|
|
28
|
-
## Wikilinks
|
|
29
|
-
|
|
30
|
-
Use `[[slug]]` syntax to link between notes. karaoke-cms resolves wikilinks automatically:
|
|
31
|
-
|
|
32
|
-
- `[[blog/hello-world]]` → `/blog/hello-world/`
|
|
33
|
-
- `[[docs/getting-started]]` → `/docs/getting-started/`
|
|
34
|
-
- `[[docs/getting-started|Getting Started]]` → link text "Getting Started"
|
|
35
|
-
|
|
36
|
-
## AI enrichment (optional)
|
|
37
|
-
|
|
38
|
-
Run `npx @karaoke-cms/enrich` to auto-generate `tags`, `description`, and `reading_time` for published notes using OpenAI or Anthropic. Skips already-enriched notes via a local cache.
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Deployment"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Deployment
|
|
6
|
-
|
|
7
|
-
> **Handbook — dev only.**
|
|
8
|
-
|
|
9
|
-
## Cloudflare Pages (recommended)
|
|
10
|
-
|
|
11
|
-
1. Push your project to a GitHub repo
|
|
12
|
-
2. Go to [Cloudflare Pages](https://pages.cloudflare.com) → Create a project → Connect to your repo
|
|
13
|
-
3. Build settings:
|
|
14
|
-
- **Build command:** `npm run build`
|
|
15
|
-
- **Build output directory:** `dist`
|
|
16
|
-
- **Node.js version:** 22
|
|
17
|
-
4. Deploy
|
|
18
|
-
|
|
19
|
-
On every push to `main`, Cloudflare Pages rebuilds and redeploys automatically.
|
|
20
|
-
|
|
21
|
-
## GitHub Actions (privacy gate)
|
|
22
|
-
|
|
23
|
-
The included `deploy.yml` workflow runs `assert-privacy` on every build to verify that no private content leaks into `dist/`. If a private note accidentally gets into the build, the deploy fails before it reaches production.
|
|
24
|
-
|
|
25
|
-
## Custom domain
|
|
26
|
-
|
|
27
|
-
In Cloudflare Pages → your project → Custom domains → Add a domain. Update `site:` in `astro.config.mjs` to match:
|
|
28
|
-
|
|
29
|
-
```js
|
|
30
|
-
export default defineConfig({
|
|
31
|
-
site: 'https://your-domain.com',
|
|
32
|
-
// ...
|
|
33
|
-
});
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Environment variables
|
|
37
|
-
|
|
38
|
-
If you use `@karaoke-cms/enrich` in CI:
|
|
39
|
-
|
|
40
|
-
| Variable | Purpose |
|
|
41
|
-
|----------|---------|
|
|
42
|
-
| `OPENAI_API_KEY` | Required if `ENRICH_PROVIDER=openai` (default) |
|
|
43
|
-
| `ANTHROPIC_API_KEY` | Required if `ENRICH_PROVIDER=anthropic` |
|
|
44
|
-
| `ENRICH_ENABLED` | Set to `true` to enable AI enrichment in CI |
|
|
45
|
-
| `CLOUDFLARE_API_TOKEN` | For Cloudflare Pages deploy via GitHub Actions |
|
|
46
|
-
| `CLOUDFLARE_ACCOUNT_ID` | For Cloudflare Pages deploy via GitHub Actions |
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Handbook"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# karaoke-cms Handbook
|
|
6
|
-
|
|
7
|
-
> **Handbook — dev only.** This section is visible at `/karaoke-cms` in dev mode and never ships to production.
|
|
8
|
-
|
|
9
|
-
karaoke-cms is an Astro framework for publishing Obsidian vaults as static sites. Private-by-default: only files with `publish: true` in frontmatter appear on your site.
|
|
10
|
-
|
|
11
|
-
## How it works
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
Obsidian vault (this directory)
|
|
15
|
-
↓ write notes with publish: true
|
|
16
|
-
↓ push to main
|
|
17
|
-
↓ GitHub Actions: astro build + assert-privacy
|
|
18
|
-
↓ Cloudflare Pages
|
|
19
|
-
↓ live site
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Your vault is also your deploy pipeline config, your documentation, and your content collection — all in one place.
|
|
23
|
-
|
|
24
|
-
## Handbook sections
|
|
25
|
-
|
|
26
|
-
- [[content]] — Writing content and frontmatter
|
|
27
|
-
- [[configuration]] — karaoke.config.ts reference
|
|
28
|
-
- [[deployment]] — Deploying to Cloudflare Pages
|
|
29
|
-
- [[privacy]] — How publish:true works
|
|
30
|
-
|
|
31
|
-
## Collections
|
|
32
|
-
|
|
33
|
-
This vault has three content collections:
|
|
34
|
-
|
|
35
|
-
| Collection | Mode | Purpose |
|
|
36
|
-
|------------|------|---------|
|
|
37
|
-
| `blog/` | dev + prod | Published blog posts |
|
|
38
|
-
| `docs/` | dev + prod | Published documentation |
|
|
39
|
-
| `karaoke-cms/` | dev only | This handbook — never ships |
|
|
40
|
-
|
|
41
|
-
Edit `content/karaoke-cms/config/collections.yaml` to add your own collections or change their visibility.
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Privacy"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Privacy Model
|
|
6
|
-
|
|
7
|
-
> **Handbook — dev only.**
|
|
8
|
-
|
|
9
|
-
## The rule
|
|
10
|
-
|
|
11
|
-
**Every file is private by default.** Only files with `publish: true` in frontmatter appear on your site.
|
|
12
|
-
|
|
13
|
-
A file without `publish: true` never enters the build — not in HTML, RSS, sitemap, or the Pagefind search index.
|
|
14
|
-
|
|
15
|
-
## How it's enforced
|
|
16
|
-
|
|
17
|
-
Two independent layers:
|
|
18
|
-
|
|
19
|
-
1. **Astro content filter** — `getCollection('blog', ({ data }) => data.publish === true)` filters at the query level. Pages only receive published entries.
|
|
20
|
-
|
|
21
|
-
2. **assert-privacy** — a post-build check that scans `dist/` for known private note titles and content. If any private content leaks, the build fails before deploy.
|
|
22
|
-
|
|
23
|
-
The collection mode system adds a third layer: `karaoke-cms/` is excluded from `makeCollections()` in production entirely. Even if a handbook page had `publish: true`, it would never enter the prod build graph.
|
|
24
|
-
|
|
25
|
-
## What "private" means
|
|
26
|
-
|
|
27
|
-
| Field | Builds? | Searchable? | In RSS? | In sitemap? |
|
|
28
|
-
|-------|---------|-------------|---------|-------------|
|
|
29
|
-
| `publish: true` | Yes | Yes | Yes | Yes |
|
|
30
|
-
| `publish: false` | No | No | No | No |
|
|
31
|
-
| missing | No | No | No | No |
|
|
32
|
-
|
|
33
|
-
## Audit your site
|
|
34
|
-
|
|
35
|
-
After every build, `assert-privacy.js` outputs a summary of what shipped. Check it in your CI logs.
|
|
36
|
-
|
|
37
|
-
For a manual check: `node node_modules/@karaoke-cms/assert-privacy/dist/index.js dist`
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "" # required — build fails without it
|
|
3
|
-
publish: false # required to appear on site (default: false)
|
|
4
|
-
date: 2026-01-15 # optional — YYYY-MM-DD, used for sorting
|
|
5
|
-
author: "" # optional — string or array ["Alice", "Bob"]
|
|
6
|
-
description: "" # optional — used in OG meta tags and RSS
|
|
7
|
-
tags: [general] # optional — enables tag pages at /tags/[tag]
|
|
8
|
-
notetype: blog
|
|
9
|
-
---
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "" # required — build fails without it
|
|
3
|
-
publish: false # required to appear on site (default: false)
|
|
4
|
-
date: 2026-01-15 # optional — YYYY-MM-DD, used for sorting
|
|
5
|
-
author: "" # optional — string or array ["Alice", "Bob"]
|
|
6
|
-
description: "" # optional — used in OG meta tags and RSS
|
|
7
|
-
tags: [general] # optional — enables tag pages at /tags/[tag]
|
|
8
|
-
notetype: blog
|
|
9
|
-
---
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "" # required — build fails without it
|
|
3
|
-
publish: false # required to appear on site (default: false)
|
|
4
|
-
date: 2026-01-15 # optional — YYYY-MM-DD, used for sorting
|
|
5
|
-
author: "" # optional — string or array ["Alice", "Bob"]
|
|
6
|
-
description: "..." # optional — used in OG meta tags and RSS
|
|
7
|
-
tags: [general] # optional — enables tag pages at /tags/[tag]
|
|
8
|
-
---
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Templates"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Templates
|
|
6
|
-
|
|
7
|
-
Obsidian templates for common note types. Use with the [Templater](https://github.com/SilentVoid13/Templater) plugin.
|
|
8
|
-
|
|
9
|
-
| Template | Use for |
|
|
10
|
-
|----------|---------|
|
|
11
|
-
| `blog-header.md` | New blog posts — sets `title`, `date`, `publish: false` |
|
|
12
|
-
| `docs-header.md` | New documentation pages |
|
|
13
|
-
| `index-by-foldernote.md` | Folder index notes (requires the folder-notes Obsidian plugin) |
|
|
14
|
-
|
|
15
|
-
In Templater settings, set the template folder to `karaoke-cms/templates`.
|