@karaoke-cms/create 0.6.2 → 0.9.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 +76 -0
- package/karaoke-create-vault/.obsidian/app.json +14 -0
- package/karaoke-create-vault/.obsidian/appearance.json +1 -0
- package/karaoke-create-vault/.obsidian/community-plugins.json +4 -0
- package/karaoke-create-vault/.obsidian/core-plugins.json +33 -0
- package/karaoke-create-vault/.obsidian/plugins/folder-notes/data.json +131 -0
- package/karaoke-create-vault/.obsidian/plugins/folder-notes/main.js +9190 -0
- package/karaoke-create-vault/.obsidian/plugins/folder-notes/manifest.json +12 -0
- package/karaoke-create-vault/.obsidian/plugins/folder-notes/styles.css +355 -0
- package/karaoke-create-vault/.obsidian/plugins/templater-obsidian/main.js +45 -0
- package/karaoke-create-vault/.obsidian/plugins/templater-obsidian/manifest.json +11 -0
- package/karaoke-create-vault/.obsidian/plugins/templater-obsidian/styles.css +226 -0
- package/karaoke-create-vault/.obsidian/workspace.json +225 -0
- package/karaoke-create-vault/blog/draft-post.md +15 -0
- package/karaoke-create-vault/blog/hello-world.md +26 -0
- package/karaoke-create-vault/docs/getting-started.md +49 -0
- package/karaoke-create-vault/docs/testing.md +0 -0
- package/karaoke-create-vault/karaoke-cms/config/collections.yaml +10 -0
- package/karaoke-create-vault/karaoke-cms/config/menus.yaml +33 -0
- package/karaoke-create-vault/karaoke-cms/manual/configuration.md +77 -0
- package/karaoke-create-vault/karaoke-cms/manual/content.md +38 -0
- package/karaoke-create-vault/karaoke-cms/manual/deployment.md +46 -0
- package/karaoke-create-vault/karaoke-cms/manual/index.md +41 -0
- package/karaoke-create-vault/karaoke-cms/manual/privacy.md +37 -0
- package/karaoke-create-vault/karaoke-cms/templates/blog-header.md +9 -0
- package/karaoke-create-vault/karaoke-cms/templates/docs-header.md +9 -0
- package/karaoke-create-vault/karaoke-cms/templates/index-by-foldernote.md +8 -0
- package/package.json +3 -2
- package/src/index.js +34 -13
- package/src/templates.js +31 -78
|
@@ -0,0 +1,38 @@
|
|
|
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.
|
|
@@ -0,0 +1,46 @@
|
|
|
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 |
|
|
@@ -0,0 +1,41 @@
|
|
|
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.
|
|
@@ -0,0 +1,37 @@
|
|
|
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`
|
|
@@ -0,0 +1,9 @@
|
|
|
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
|
+
---
|
|
@@ -0,0 +1,9 @@
|
|
|
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
|
+
---
|
|
@@ -0,0 +1,8 @@
|
|
|
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
|
+
---
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karaoke-cms/create",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.0",
|
|
5
5
|
"description": "Scaffold a new karaoke-cms project",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-karaoke-cms": "./src/index.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
|
-
"src/"
|
|
10
|
+
"src/",
|
|
11
|
+
"karaoke-create-vault/"
|
|
11
12
|
],
|
|
12
13
|
"engines": {
|
|
13
14
|
"node": ">=22.12.0"
|
package/src/index.js
CHANGED
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { createInterface } from 'readline';
|
|
10
|
-
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
10
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, cpSync } from 'fs';
|
|
11
11
|
import { join, resolve } from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { spawnSync } from 'child_process';
|
|
12
14
|
import {
|
|
13
15
|
packageJson, astroConfig, karaokeConfig, contentConfig,
|
|
14
|
-
envDts, tsConfig, gitignore, cloudflareRedirects,
|
|
15
|
-
helloWorld, draftPost, gettingStarted,
|
|
16
|
+
envDts, tsConfig, gitignore, envDefault, cloudflareRedirects,
|
|
16
17
|
} from './templates.js';
|
|
17
18
|
|
|
18
19
|
// ── ANSI helpers ─────────────────────────────────────────────────────────────
|
|
@@ -109,7 +110,10 @@ async function main() {
|
|
|
109
110
|
const title = await ask('Site title', defaultTitle);
|
|
110
111
|
const siteUrl = await ask('Site URL', 'https://my-site.pages.dev');
|
|
111
112
|
const description = await ask('Description', 'Our team knowledge base.');
|
|
112
|
-
const
|
|
113
|
+
const themeChoice = await askChoice('Theme', ['default', 'minimal', 'blog'], 0);
|
|
114
|
+
const theme = themeChoice === 'default' || themeChoice === 'minimal'
|
|
115
|
+
? themeChoice
|
|
116
|
+
: `@karaoke-cms/theme-${themeChoice}`;
|
|
113
117
|
const search = await askYesNo('Enable search? (Pagefind)', true);
|
|
114
118
|
const commentsEnabled = await askYesNo('Enable comments? (requires Giscus setup)', false);
|
|
115
119
|
|
|
@@ -128,25 +132,20 @@ async function main() {
|
|
|
128
132
|
// ── Scaffold ────────────────────────────────────────────────────────────────
|
|
129
133
|
console.log(`\n Scaffolding ${BOLD}${dir}${R}...\n`);
|
|
130
134
|
|
|
131
|
-
const date = new Date().toISOString().split('T')[0];
|
|
132
|
-
|
|
133
135
|
mkdirSync(join(targetDir, 'src'), { recursive: true });
|
|
134
|
-
mkdirSync(join(targetDir, 'content/blog'), { recursive: true });
|
|
135
|
-
mkdirSync(join(targetDir, 'content/docs'), { recursive: true });
|
|
136
136
|
mkdirSync(join(targetDir, 'public'), { recursive: true });
|
|
137
137
|
|
|
138
|
+
// Config and project files from templates
|
|
138
139
|
const files = {
|
|
139
|
-
'package.json': packageJson({ name: dir, astroVersion }),
|
|
140
|
+
'package.json': packageJson({ name: dir, astroVersion, theme }),
|
|
140
141
|
'astro.config.mjs': astroConfig({ siteUrl }),
|
|
141
142
|
'karaoke.config.ts': karaokeConfig({ title, description, theme, search, comments }),
|
|
142
143
|
'src/content.config.ts': contentConfig(),
|
|
143
144
|
'src/env.d.ts': envDts(),
|
|
144
145
|
'tsconfig.json': tsConfig(),
|
|
145
146
|
'.gitignore': gitignore(),
|
|
147
|
+
'.env.default': envDefault(),
|
|
146
148
|
'public/_redirects': cloudflareRedirects(),
|
|
147
|
-
'content/blog/hello-world.md': helloWorld({ date }),
|
|
148
|
-
'content/blog/draft-post.md': draftPost({ date }),
|
|
149
|
-
'content/docs/getting-started.md': gettingStarted({ date }),
|
|
150
149
|
};
|
|
151
150
|
|
|
152
151
|
for (const [file, content] of Object.entries(files)) {
|
|
@@ -154,13 +153,35 @@ async function main() {
|
|
|
154
153
|
console.log(` ${GREEN}+${R} ${file}`);
|
|
155
154
|
}
|
|
156
155
|
|
|
156
|
+
// Vault content: copy the real Obsidian vault into vault/ subdirectory
|
|
157
|
+
const vaultSrc = fileURLToPath(new URL('../karaoke-create-vault', import.meta.url));
|
|
158
|
+
cpSync(vaultSrc, join(targetDir, 'vault'), { recursive: true });
|
|
159
|
+
console.log(` ${GREEN}+${R} vault/ (Obsidian vault)`);
|
|
160
|
+
|
|
161
|
+
// ── Git init ────────────────────────────────────────────────────────────────
|
|
162
|
+
const gitOk = (() => {
|
|
163
|
+
const run = (args) => spawnSync('git', args, { cwd: targetDir, encoding: 'utf8' }).status === 0;
|
|
164
|
+
return (
|
|
165
|
+
run(['init']) &&
|
|
166
|
+
run(['add', '-A']) &&
|
|
167
|
+
run(['-c', 'user.name=karaoke-cms', '-c', 'user.email=setup@karaoke-cms.org',
|
|
168
|
+
'commit', '-m', 'chore: initial karaoke-cms setup'])
|
|
169
|
+
);
|
|
170
|
+
})();
|
|
171
|
+
|
|
172
|
+
if (gitOk) {
|
|
173
|
+
console.log(` ${GREEN}+${R} git repository initialized`);
|
|
174
|
+
} else {
|
|
175
|
+
console.log(` ${GRAY} (git init skipped — install git and run it manually)${R}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
157
178
|
// ── Done ────────────────────────────────────────────────────────────────────
|
|
158
179
|
console.log(`\n${GREEN}✓${R} Done! Created ${BOLD}${dir}/${R}\n`);
|
|
159
180
|
console.log(` Next steps:\n`);
|
|
160
181
|
console.log(` ${CYAN}cd ${dir}${R}`);
|
|
161
182
|
console.log(` ${CYAN}npm install${R}`);
|
|
162
183
|
console.log(` ${CYAN}npm run dev${R} ${GRAY}→ http://localhost:4321${R}\n`);
|
|
163
|
-
console.log(` ${GRAY}Open ${BOLD}${dir}/${R}${GRAY} in Obsidian
|
|
184
|
+
console.log(` ${GRAY}Open ${BOLD}${dir}/vault/${R}${GRAY} in Obsidian to write content.${R}\n`);
|
|
164
185
|
}
|
|
165
186
|
|
|
166
187
|
main().catch(err => {
|
package/src/templates.js
CHANGED
|
@@ -5,9 +5,16 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @param {{ name: string, astroVersion: string }} opts
|
|
8
|
+
* @param {{ name: string, astroVersion: string, theme?: string }} opts
|
|
9
9
|
*/
|
|
10
|
-
export function packageJson({ name, astroVersion }) {
|
|
10
|
+
export function packageJson({ name, astroVersion, theme }) {
|
|
11
|
+
const dependencies = {
|
|
12
|
+
'@karaoke-cms/astro': `^${astroVersion}`,
|
|
13
|
+
astro: '^6.0.0',
|
|
14
|
+
};
|
|
15
|
+
if (theme?.startsWith('@')) {
|
|
16
|
+
dependencies[theme] = `^${astroVersion}`;
|
|
17
|
+
}
|
|
11
18
|
return JSON.stringify({
|
|
12
19
|
name,
|
|
13
20
|
private: true,
|
|
@@ -18,10 +25,7 @@ export function packageJson({ name, astroVersion }) {
|
|
|
18
25
|
build: 'astro build',
|
|
19
26
|
preview: 'astro preview',
|
|
20
27
|
},
|
|
21
|
-
dependencies
|
|
22
|
-
'@karaoke-cms/astro': `^${astroVersion}`,
|
|
23
|
-
astro: '^6.0.0',
|
|
24
|
-
},
|
|
28
|
+
dependencies,
|
|
25
29
|
}, null, 2) + '\n';
|
|
26
30
|
}
|
|
27
31
|
|
|
@@ -66,8 +70,12 @@ export function karaokeConfig({ title, description, theme, search, comments }) {
|
|
|
66
70
|
: '';
|
|
67
71
|
|
|
68
72
|
return `import type { KaraokeConfig } from '@karaoke-cms/astro';
|
|
73
|
+
import { loadEnv } from '@karaoke-cms/astro/env';
|
|
74
|
+
|
|
75
|
+
const env = loadEnv(new URL('.', import.meta.url));
|
|
69
76
|
|
|
70
77
|
const config: KaraokeConfig = {
|
|
78
|
+
vault: env.KARAOKE_VAULT,
|
|
71
79
|
title: ${JSON.stringify(title)},
|
|
72
80
|
description: ${JSON.stringify(description)},
|
|
73
81
|
theme: ${JSON.stringify(theme)},${modulesStr}
|
|
@@ -79,8 +87,11 @@ export default config;
|
|
|
79
87
|
|
|
80
88
|
export function contentConfig() {
|
|
81
89
|
return `import { makeCollections } from '@karaoke-cms/astro/collections';
|
|
90
|
+
import { loadEnv } from '@karaoke-cms/astro/env';
|
|
91
|
+
|
|
92
|
+
const env = loadEnv(new URL('..', import.meta.url));
|
|
82
93
|
|
|
83
|
-
export const collections = makeCollections(new URL('..', import.meta.url));
|
|
94
|
+
export const collections = makeCollections(new URL('..', import.meta.url), env.KARAOKE_VAULT);
|
|
84
95
|
`;
|
|
85
96
|
}
|
|
86
97
|
|
|
@@ -103,82 +114,24 @@ node_modules/
|
|
|
103
114
|
dist/
|
|
104
115
|
.astro/
|
|
105
116
|
.env
|
|
106
|
-
.env
|
|
117
|
+
.env.local
|
|
118
|
+
.env.*.local
|
|
119
|
+
# Obsidian workspace state (personal, not shared)
|
|
120
|
+
.obsidian/workspace.json
|
|
121
|
+
.obsidian/workspace-mobile.json
|
|
107
122
|
`;
|
|
108
123
|
}
|
|
109
124
|
|
|
110
|
-
export function
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return `---
|
|
117
|
-
title: "Hello World"
|
|
118
|
-
publish: true
|
|
119
|
-
date: ${date}
|
|
120
|
-
author: "The Team"
|
|
121
|
-
description: "Our first published post."
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
Welcome! This post has \`publish: true\` so it appears on the site.
|
|
125
|
-
|
|
126
|
-
## How publishing works
|
|
127
|
-
|
|
128
|
-
1. Write Markdown in Obsidian (or any editor)
|
|
129
|
-
2. Add \`publish: true\` to the frontmatter when ready to share
|
|
130
|
-
3. Push to \`main\` — GitHub Actions builds and deploys automatically
|
|
131
|
-
|
|
132
|
-
Posts without \`publish: true\` stay private in your vault.
|
|
125
|
+
export function envDefault() {
|
|
126
|
+
return `# Obsidian vault location — open this folder in Obsidian to write content.
|
|
127
|
+
# Override in .env (gitignored) to point to a vault elsewhere on your machine.
|
|
128
|
+
# Absolute path: KARAOKE_VAULT=/Users/you/Obsidian/my-vault
|
|
129
|
+
# Relative path: KARAOKE_VAULT=../my-obsidian-vault
|
|
130
|
+
KARAOKE_VAULT=./vault/
|
|
133
131
|
`;
|
|
134
132
|
}
|
|
135
133
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return `---
|
|
139
|
-
title: "Draft Post"
|
|
140
|
-
publish: false
|
|
141
|
-
date: ${date}
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
This post has \`publish: false\`. It lives in your vault but never appears on the site.
|
|
145
|
-
|
|
146
|
-
Change it to \`publish: true\` when you're ready to share it.
|
|
147
|
-
`;
|
|
134
|
+
export function cloudflareRedirects() {
|
|
135
|
+
return `/* /404.html 404\n`;
|
|
148
136
|
}
|
|
149
137
|
|
|
150
|
-
/** @param {{ date: string }} opts */
|
|
151
|
-
export function gettingStarted({ date }) {
|
|
152
|
-
return `---
|
|
153
|
-
title: "Getting Started"
|
|
154
|
-
publish: true
|
|
155
|
-
date: ${date}
|
|
156
|
-
description: "How to set up and use your karaoke-cms site."
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
## Setup
|
|
160
|
-
|
|
161
|
-
1. Open this folder in Obsidian as a vault
|
|
162
|
-
2. Edit \`karaoke.config.ts\` — set your title, theme, and modules
|
|
163
|
-
3. Set your Cloudflare Pages URL in \`astro.config.mjs\`
|
|
164
|
-
4. Push to \`main\` — your site is live
|
|
165
|
-
|
|
166
|
-
## Writing content
|
|
167
|
-
|
|
168
|
-
- Blog posts go in \`content/blog/\`
|
|
169
|
-
- Documentation goes in \`content/docs/\`
|
|
170
|
-
- Set \`publish: true\` to make a file public
|
|
171
|
-
|
|
172
|
-
## Frontmatter reference
|
|
173
|
-
|
|
174
|
-
\`\`\`yaml
|
|
175
|
-
---
|
|
176
|
-
title: "My Post" # required
|
|
177
|
-
publish: true # required to appear on site
|
|
178
|
-
date: 2026-01-15 # optional, YYYY-MM-DD
|
|
179
|
-
author: "Name" # optional
|
|
180
|
-
description: "..." # optional, used in OG tags and RSS
|
|
181
|
-
---
|
|
182
|
-
\`\`\`
|
|
183
|
-
`;
|
|
184
|
-
}
|