@karaoke-cms/create 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/karaoke-create-vault/.obsidian/workspace.json +7 -5
- package/karaoke-create-vault/karaoke-cms/config/index.md +14 -0
- package/karaoke-create-vault/karaoke-cms/config/menus.yaml +26 -1
- package/karaoke-create-vault/karaoke-cms/templates/index.md +15 -0
- package/package.json +2 -2
- package/src/index.js +90 -9
- package/src/templates.js +19 -0
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
"state": {
|
|
28
28
|
"type": "markdown",
|
|
29
29
|
"state": {
|
|
30
|
-
"file": "karaoke-cms/
|
|
30
|
+
"file": "karaoke-cms/manual/configuration.md",
|
|
31
31
|
"mode": "source",
|
|
32
32
|
"source": false
|
|
33
33
|
},
|
|
34
34
|
"icon": "lucide-file",
|
|
35
|
-
"title": "
|
|
35
|
+
"title": "configuration"
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
],
|
|
@@ -183,10 +183,10 @@
|
|
|
183
183
|
"state": {
|
|
184
184
|
"type": "file-properties",
|
|
185
185
|
"state": {
|
|
186
|
-
"file": "karaoke-cms/
|
|
186
|
+
"file": "karaoke-cms/manual/configuration.md"
|
|
187
187
|
},
|
|
188
188
|
"icon": "lucide-info",
|
|
189
|
-
"title": "File properties for
|
|
189
|
+
"title": "File properties for configuration"
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
],
|
|
@@ -210,8 +210,10 @@
|
|
|
210
210
|
},
|
|
211
211
|
"active": "52e565c48d7a7c39",
|
|
212
212
|
"lastOpenFiles": [
|
|
213
|
-
"karaoke-cms/templates/
|
|
213
|
+
"karaoke-cms/templates/index.md",
|
|
214
|
+
"karaoke-cms/config/index.md",
|
|
214
215
|
"karaoke-cms/templates/docs-header.md",
|
|
216
|
+
"karaoke-cms/templates/blog-header.md",
|
|
215
217
|
"karaoke-cms/templates/index-by-foldernote.md",
|
|
216
218
|
"karaoke-cms/manual/content.md",
|
|
217
219
|
"karaoke-cms/manual/configuration.md",
|
|
@@ -0,0 +1,14 @@
|
|
|
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.
|
|
@@ -24,9 +24,34 @@ menus:
|
|
|
24
24
|
- text: Tags
|
|
25
25
|
href: /tags
|
|
26
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
|
|
27
52
|
|
|
28
53
|
footer:
|
|
29
|
-
orientation:
|
|
54
|
+
orientation: vertical
|
|
30
55
|
entries:
|
|
31
56
|
- text: RSS
|
|
32
57
|
href: /rss.xml
|
|
@@ -0,0 +1,15 @@
|
|
|
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`.
|
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.1",
|
|
5
5
|
"description": "Scaffold a new karaoke-cms project",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-karaoke-cms": "./src/index.js"
|
|
@@ -24,6 +24,6 @@
|
|
|
24
24
|
"vitest": "^4.1.1"
|
|
25
25
|
},
|
|
26
26
|
"scripts": {
|
|
27
|
-
"test": "vitest run test/templates.test.js"
|
|
27
|
+
"test": "vitest run test/templates.test.js test/index.test.js"
|
|
28
28
|
}
|
|
29
29
|
}
|
package/src/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { fileURLToPath } from 'url';
|
|
|
13
13
|
import { spawnSync } from 'child_process';
|
|
14
14
|
import {
|
|
15
15
|
packageJson, astroConfig, karaokeConfig, contentConfig,
|
|
16
|
-
envDts, tsConfig, gitignore, envDefault, cloudflareRedirects,
|
|
16
|
+
envDts, tsConfig, gitignore, envDefault, cloudflareRedirects, slugify,
|
|
17
17
|
} from './templates.js';
|
|
18
18
|
|
|
19
19
|
// ── ANSI helpers ─────────────────────────────────────────────────────────────
|
|
@@ -108,7 +108,6 @@ async function main() {
|
|
|
108
108
|
.replace(/\b\w/g, c => c.toUpperCase());
|
|
109
109
|
|
|
110
110
|
const title = await ask('Site title', defaultTitle);
|
|
111
|
-
const siteUrl = await ask('Site URL', 'https://my-site.pages.dev');
|
|
112
111
|
const description = await ask('Description', 'Our team knowledge base.');
|
|
113
112
|
const themeChoice = await askChoice('Theme', ['default', 'minimal', 'blog'], 0);
|
|
114
113
|
const theme = themeChoice === 'default' || themeChoice === 'minimal'
|
|
@@ -127,14 +126,15 @@ async function main() {
|
|
|
127
126
|
comments = { repo, repoId, category, categoryId };
|
|
128
127
|
}
|
|
129
128
|
|
|
130
|
-
rl.close();
|
|
131
|
-
|
|
132
129
|
// ── Scaffold ────────────────────────────────────────────────────────────────
|
|
133
130
|
console.log(`\n Scaffolding ${BOLD}${dir}${R}...\n`);
|
|
134
131
|
|
|
135
132
|
mkdirSync(join(targetDir, 'src'), { recursive: true });
|
|
136
133
|
mkdirSync(join(targetDir, 'public'), { recursive: true });
|
|
137
134
|
|
|
135
|
+
// siteUrl placeholder — replaced with the real *.pages.dev URL after deploy
|
|
136
|
+
const siteUrl = 'https://your-site.pages.dev';
|
|
137
|
+
|
|
138
138
|
// Config and project files from templates
|
|
139
139
|
const files = {
|
|
140
140
|
'package.json': packageJson({ name: dir, astroVersion, theme }),
|
|
@@ -175,12 +175,36 @@ async function main() {
|
|
|
175
175
|
console.log(` ${GRAY} (git init skipped — install git and run it manually)${R}`);
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
// ──
|
|
178
|
+
// ── npm install ──────────────────────────────────────────────────────────────
|
|
179
|
+
console.log(`\n Installing dependencies...\n`);
|
|
180
|
+
const installResult = spawnSync('npm', ['install'], { cwd: targetDir, stdio: 'inherit' });
|
|
181
|
+
if (installResult.status !== 0) {
|
|
182
|
+
console.log(` ${GRAY}(install failed — run npm install manually)${R}`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ── Deploy prompt ────────────────────────────────────────────────────────────
|
|
186
|
+
const deployNow = await askYesNo('Publish a live preview to Cloudflare Pages now?', false);
|
|
187
|
+
|
|
188
|
+
rl.close();
|
|
189
|
+
|
|
190
|
+
let liveUrl = null;
|
|
191
|
+
if (deployNow) {
|
|
192
|
+
const projectName = `${slugify(dir)}-preview`;
|
|
193
|
+
liveUrl = await deployToCloudflare(targetDir, projectName);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ── Success screen ───────────────────────────────────────────────────────────
|
|
179
197
|
console.log(`\n${GREEN}✓${R} Done! Created ${BOLD}${dir}/${R}\n`);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
198
|
+
if (liveUrl) {
|
|
199
|
+
console.log(` ${BOLD}🎤 Live:${R} ${liveUrl}`);
|
|
200
|
+
console.log(` ${BOLD}💻 Dev:${R} ${CYAN}cd ${dir} && npm run dev${R}`);
|
|
201
|
+
console.log(` ${BOLD}🔄 Redeploy:${R} ${CYAN}npm run deploy${R}\n`);
|
|
202
|
+
} else {
|
|
203
|
+
console.log(` Next steps:\n`);
|
|
204
|
+
console.log(` ${CYAN}cd ${dir}${R}`);
|
|
205
|
+
console.log(` ${CYAN}npm run dev${R} ${GRAY}→ http://localhost:4321${R}`);
|
|
206
|
+
console.log(` ${CYAN}npm run deploy${R} ${GRAY}→ publish to Cloudflare Pages${R}\n`);
|
|
207
|
+
}
|
|
184
208
|
console.log(` ${GRAY}Open ${BOLD}${dir}/vault/${R}${GRAY} in Obsidian to write content.${R}\n`);
|
|
185
209
|
}
|
|
186
210
|
|
|
@@ -188,3 +212,60 @@ main().catch(err => {
|
|
|
188
212
|
console.error(`\n${RED}✗${R} ${err.message}`);
|
|
189
213
|
process.exit(1);
|
|
190
214
|
});
|
|
215
|
+
|
|
216
|
+
// ── Cloudflare Pages deploy ───────────────────────────────────────────────────
|
|
217
|
+
export async function deployToCloudflare(targetDir, projectName) {
|
|
218
|
+
console.log(`\n ${BOLD}Deploying to Cloudflare Pages...${R}\n`);
|
|
219
|
+
|
|
220
|
+
// 1. Check if logged in
|
|
221
|
+
const whoami = spawnSync('npx', ['wrangler', 'whoami', '--json'],
|
|
222
|
+
{ cwd: targetDir, encoding: 'utf8' });
|
|
223
|
+
|
|
224
|
+
if (whoami.status !== 0 || whoami.stdout.includes('You are not authenticated')) {
|
|
225
|
+
console.log(` ${CYAN}Opening Cloudflare login...${R}`);
|
|
226
|
+
const login = spawnSync('npx', ['wrangler', 'login'],
|
|
227
|
+
{ cwd: targetDir, stdio: 'inherit' });
|
|
228
|
+
if (login.status !== 0) {
|
|
229
|
+
console.log(` ${GRAY}Login cancelled — run 'npm run deploy' when ready.${R}`);
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 2. Build
|
|
235
|
+
console.log(` ${CYAN}Building...${R}`);
|
|
236
|
+
const build = spawnSync('npm', ['run', 'build'],
|
|
237
|
+
{ cwd: targetDir, stdio: 'inherit' });
|
|
238
|
+
if (build.status !== 0) {
|
|
239
|
+
console.log(` ${RED}Build failed — run 'npm run deploy' when ready.${R}`);
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 3. Create Pages project — best-effort, ignore failure (project may already exist on re-run)
|
|
244
|
+
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
245
|
+
const createArgs = ['wrangler', 'pages', 'project', 'create', projectName,
|
|
246
|
+
'--production-branch', 'main'];
|
|
247
|
+
if (accountId) createArgs.push('--account-id', accountId);
|
|
248
|
+
spawnSync('npx', createArgs, { cwd: targetDir, stdio: 'pipe' });
|
|
249
|
+
|
|
250
|
+
// 4. Deploy — stdio: inherit so wrangler output + interactive prompts (e.g. account picker) are visible
|
|
251
|
+
console.log(` ${CYAN}Uploading...${R}`);
|
|
252
|
+
const deployArgs = ['wrangler', 'pages', 'deploy', 'dist',
|
|
253
|
+
`--project-name=${projectName}`];
|
|
254
|
+
if (accountId) deployArgs.push('--account-id', accountId);
|
|
255
|
+
const deploy = spawnSync('npx', deployArgs, { cwd: targetDir, stdio: 'inherit' });
|
|
256
|
+
|
|
257
|
+
if (deploy.status !== 0) {
|
|
258
|
+
console.log(` ${RED}Deploy failed — run 'npm run deploy' when ready.${R}`);
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// 5. URL is deterministic — no need to parse wrangler stdout
|
|
263
|
+
const liveUrl = `https://${projectName}.pages.dev`;
|
|
264
|
+
|
|
265
|
+
// 6. Write real URL back to astro.config.mjs (replaces placeholder set during scaffold)
|
|
266
|
+
const configPath = join(targetDir, 'astro.config.mjs');
|
|
267
|
+
const configSrc = readFileSync(configPath, 'utf8');
|
|
268
|
+
writeFileSync(configPath, configSrc.replace('https://your-site.pages.dev', liveUrl));
|
|
269
|
+
|
|
270
|
+
return liveUrl;
|
|
271
|
+
}
|
package/src/templates.js
CHANGED
|
@@ -4,10 +4,25 @@
|
|
|
4
4
|
* Exported separately so they're independently testable.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Compute a Cloudflare-safe project slug from a directory name.
|
|
9
|
+
* Rules: lowercase, spaces/underscores → hyphens, non-alphanumeric stripped,
|
|
10
|
+
* truncated to 24 chars (leaves room for the -preview suffix within CF's 28-char limit).
|
|
11
|
+
* @param {string} dir
|
|
12
|
+
*/
|
|
13
|
+
export function slugify(dir) {
|
|
14
|
+
return dir
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.replace(/[\s_]+/g, '-')
|
|
17
|
+
.replace(/[^a-z0-9-]/g, '')
|
|
18
|
+
.slice(0, 24);
|
|
19
|
+
}
|
|
20
|
+
|
|
7
21
|
/**
|
|
8
22
|
* @param {{ name: string, astroVersion: string, theme?: string }} opts
|
|
9
23
|
*/
|
|
10
24
|
export function packageJson({ name, astroVersion, theme }) {
|
|
25
|
+
const projectSlug = slugify(name);
|
|
11
26
|
const dependencies = {
|
|
12
27
|
'@karaoke-cms/astro': `^${astroVersion}`,
|
|
13
28
|
astro: '^6.0.0',
|
|
@@ -24,8 +39,12 @@ export function packageJson({ name, astroVersion, theme }) {
|
|
|
24
39
|
dev: 'astro dev',
|
|
25
40
|
build: 'astro build',
|
|
26
41
|
preview: 'astro preview',
|
|
42
|
+
deploy: `astro build && npx wrangler pages deploy dist --project-name=${projectSlug}-preview`,
|
|
27
43
|
},
|
|
28
44
|
dependencies,
|
|
45
|
+
devDependencies: {
|
|
46
|
+
wrangler: '^3',
|
|
47
|
+
},
|
|
29
48
|
}, null, 2) + '\n';
|
|
30
49
|
}
|
|
31
50
|
|