supaslidev 0.4.1 → 0.4.2
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/dist/cli/index.js +49 -24
- package/dist/index.d.ts +1 -0
- package/package.json +2 -2
- package/src/cli/commands/deploy.ts +41 -12
- package/src/cli/commands/thumbnail.ts +22 -9
- package/src/cli/index.ts +2 -1
- package/src/shared/presentations.ts +3 -0
- package/src/shared/types.ts +1 -0
package/dist/cli/index.js
CHANGED
|
@@ -206,11 +206,13 @@ function regeneratePresentationsJson(presentationsDir, presentationsJsonPath, op
|
|
|
206
206
|
return isDir && hasSlides;
|
|
207
207
|
}).map((name) => {
|
|
208
208
|
const frontmatter = parseFrontmatter(readFileSync(join(presentationsDir, name, "slides.md"), "utf-8"));
|
|
209
|
+
const colorSchema = frontmatter.colorSchema;
|
|
209
210
|
const presentation = {
|
|
210
211
|
id: name,
|
|
211
212
|
title: frontmatter.title || name,
|
|
212
213
|
description: extractDescription(frontmatter.info) || "",
|
|
213
214
|
theme: frontmatter.theme || "default",
|
|
215
|
+
colorSchema: colorSchema || "",
|
|
214
216
|
background: frontmatter.background || "",
|
|
215
217
|
duration: frontmatter.duration || ""
|
|
216
218
|
};
|
|
@@ -186676,7 +186678,7 @@ var require_ts_morph = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
186676
186678
|
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
186677
186679
|
require_dist$2();
|
|
186678
186680
|
require_ts_morph();
|
|
186679
|
-
const CLI_VERSION = "0.4.
|
|
186681
|
+
const CLI_VERSION = "0.4.2";
|
|
186680
186682
|
const PACKAGE_NAME = "@supaslidev/cli";
|
|
186681
186683
|
const CACHE_DIR = join(tmpdir(), "supaslidev-cli");
|
|
186682
186684
|
const CACHE_FILE = join(CACHE_DIR, "version-cache.json");
|
|
@@ -188029,11 +188031,11 @@ function findNuxtBin(projectRoot, supaslidevRoot) {
|
|
|
188029
188031
|
}
|
|
188030
188032
|
function createVercelConfig(basePath, presentations) {
|
|
188031
188033
|
const rewrites = presentations.map((id) => ({
|
|
188032
|
-
source: `${basePath}presentations/${id}
|
|
188034
|
+
source: `${basePath}presentations/${id}/:path((?!.*\\.).*)`,
|
|
188033
188035
|
destination: `${basePath}presentations/${id}/index.html`
|
|
188034
188036
|
}));
|
|
188035
188037
|
rewrites.push({
|
|
188036
|
-
source: `${basePath}(.*)`,
|
|
188038
|
+
source: `${basePath}:path((?!.*\\.).*)`,
|
|
188037
188039
|
destination: `${basePath}index.html`
|
|
188038
188040
|
});
|
|
188039
188041
|
return JSON.stringify({ rewrites }, null, 2);
|
|
@@ -188067,7 +188069,7 @@ async function deploy(options = {}) {
|
|
|
188067
188069
|
const presentationsDir = join(projectRoot, "presentations");
|
|
188068
188070
|
const presentations = getPresentations$1(presentationsDir);
|
|
188069
188071
|
if (presentations.length === 0) throw new Error("No presentations found in the presentations directory.");
|
|
188070
|
-
const outputDir = resolve(options.output ??
|
|
188072
|
+
const outputDir = resolve(projectRoot, options.output ?? "deploy");
|
|
188071
188073
|
const resolvedProjectRoot = resolve(projectRoot);
|
|
188072
188074
|
if (!outputDir.startsWith(resolvedProjectRoot)) throw new Error(`Output directory "${outputDir}" is outside the project root "${resolvedProjectRoot}". Use a path within your project.`);
|
|
188073
188075
|
const basePath = (options.base ?? "/").replace(/\/*$/, "/");
|
|
@@ -188103,17 +188105,21 @@ async function deploy(options = {}) {
|
|
|
188103
188105
|
const slidevBin = join(presentationDir, "node_modules", ".bin", "slidev");
|
|
188104
188106
|
const outputBase = join(thumbnailsDir, id);
|
|
188105
188107
|
const targetFile = join(thumbnailsDir, `${id}.png`);
|
|
188106
|
-
|
|
188108
|
+
const slidesPath = join(presentationDir, "slides.md");
|
|
188109
|
+
const useDark = (existsSync(slidesPath) ? parseFrontmatter(readFileSync(slidesPath, "utf-8")) : {}).colorSchema === "dark";
|
|
188110
|
+
console.log(` Thumbnail: ${id}${useDark ? " (dark mode)" : ""}`);
|
|
188111
|
+
const exportArgs = [
|
|
188112
|
+
"export",
|
|
188113
|
+
"--format",
|
|
188114
|
+
"png",
|
|
188115
|
+
"--range",
|
|
188116
|
+
"1",
|
|
188117
|
+
"--output",
|
|
188118
|
+
outputBase
|
|
188119
|
+
];
|
|
188120
|
+
if (useDark) exportArgs.push("--dark");
|
|
188107
188121
|
try {
|
|
188108
|
-
await runCommand(slidevBin,
|
|
188109
|
-
"export",
|
|
188110
|
-
"--format",
|
|
188111
|
-
"png",
|
|
188112
|
-
"--range",
|
|
188113
|
-
"1",
|
|
188114
|
-
"--output",
|
|
188115
|
-
outputBase
|
|
188116
|
-
], { cwd: presentationDir });
|
|
188122
|
+
await runCommand(slidevBin, exportArgs, { cwd: presentationDir });
|
|
188117
188123
|
if (!existsSync(targetFile) && existsSync(outputBase)) {
|
|
188118
188124
|
const pngs = readdirSync(outputBase).filter((f) => f.endsWith(".png")).sort();
|
|
188119
188125
|
if (pngs.length > 0) renameSync(join(outputBase, pngs[0]), targetFile);
|
|
@@ -188131,6 +188137,7 @@ async function deploy(options = {}) {
|
|
|
188131
188137
|
const nuxtEnv = {
|
|
188132
188138
|
...process.env,
|
|
188133
188139
|
NODE_ENV: "production",
|
|
188140
|
+
NITRO_PRESET: process.env.NITRO_PRESET ?? "static",
|
|
188134
188141
|
SUPASLIDEV_PROJECT_ROOT: projectRoot,
|
|
188135
188142
|
SUPASLIDEV_PRESENTATIONS_DIR: presentationsDir,
|
|
188136
188143
|
NUXT_PUBLIC_DEPLOY_MODE: "true"
|
|
@@ -188173,6 +188180,17 @@ async function deploy(options = {}) {
|
|
|
188173
188180
|
writeFileSync(join(outputDir, "vercel.json"), createVercelConfig(basePath, presentations));
|
|
188174
188181
|
writeFileSync(join(outputDir, "netlify.toml"), createNetlifyConfig(basePath, presentations));
|
|
188175
188182
|
writeFileSync(join(outputDir, "package.json"), createDeployPackageJson());
|
|
188183
|
+
const rootVercelJson = join(projectRoot, "vercel.json");
|
|
188184
|
+
if (!existsSync(rootVercelJson)) {
|
|
188185
|
+
const vercelConfig = {
|
|
188186
|
+
framework: null,
|
|
188187
|
+
installCommand: `${existsSync(join(projectRoot, "pnpm-lock.yaml")) ? "pnpm" : existsSync(join(projectRoot, "yarn.lock")) ? "yarn" : "npm"} install`,
|
|
188188
|
+
buildCommand: "npx supaslidev deploy --output dist",
|
|
188189
|
+
outputDirectory: "dist"
|
|
188190
|
+
};
|
|
188191
|
+
writeFileSync(rootVercelJson, JSON.stringify(vercelConfig, null, 2) + "\n");
|
|
188192
|
+
console.log(" Generated vercel.json in project root for Vercel deployment.\n");
|
|
188193
|
+
}
|
|
188176
188194
|
console.log("=".repeat(50));
|
|
188177
188195
|
console.log(" Deploy package ready!");
|
|
188178
188196
|
console.log("=".repeat(50));
|
|
@@ -188210,16 +188228,23 @@ async function thumbnail(name, options = {}) {
|
|
|
188210
188228
|
console.log(` Generating thumbnail: ${name}`);
|
|
188211
188229
|
console.log("=".repeat(50) + "\n");
|
|
188212
188230
|
const slidevBin = join(presentationDir, "node_modules", ".bin", "slidev");
|
|
188231
|
+
let useDark = options.dark ?? false;
|
|
188232
|
+
if (options.dark === void 0) {
|
|
188233
|
+
const slidesPath = join(presentationDir, "slides.md");
|
|
188234
|
+
if (existsSync(slidesPath)) useDark = parseFrontmatter(readFileSync(slidesPath, "utf-8")).colorSchema === "dark";
|
|
188235
|
+
}
|
|
188236
|
+
const exportArgs = [
|
|
188237
|
+
"export",
|
|
188238
|
+
"--format",
|
|
188239
|
+
"png",
|
|
188240
|
+
"--range",
|
|
188241
|
+
"1",
|
|
188242
|
+
"--output",
|
|
188243
|
+
outputPath
|
|
188244
|
+
];
|
|
188245
|
+
if (useDark) exportArgs.push("--dark");
|
|
188213
188246
|
await new Promise((resolve) => {
|
|
188214
|
-
const slidev = spawn(slidevBin,
|
|
188215
|
-
"export",
|
|
188216
|
-
"--format",
|
|
188217
|
-
"png",
|
|
188218
|
-
"--range",
|
|
188219
|
-
"1",
|
|
188220
|
-
"--output",
|
|
188221
|
-
outputPath
|
|
188222
|
-
], {
|
|
188247
|
+
const slidev = spawn(slidevBin, exportArgs, {
|
|
188223
188248
|
cwd: presentationDir,
|
|
188224
188249
|
stdio: "inherit"
|
|
188225
188250
|
});
|
|
@@ -188271,7 +188296,7 @@ program.command("import").description("Import existing Sli.dev presentation(s)")
|
|
|
188271
188296
|
install: options.install ?? true
|
|
188272
188297
|
});
|
|
188273
188298
|
});
|
|
188274
|
-
program.command("thumbnail").description("Generate a PNG thumbnail of the first slide").argument("<name>", "Name of the presentation").option("-o, --output <path>", "Output path for the thumbnail (without extension)").action(async (name, options) => {
|
|
188299
|
+
program.command("thumbnail").description("Generate a PNG thumbnail of the first slide").argument("<name>", "Name of the presentation").option("-o, --output <path>", "Output path for the thumbnail (without extension)").option("--dark", "Export as dark theme (auto-detected from colorSchema if not set)").action(async (name, options) => {
|
|
188275
188300
|
await thumbnail(name, options);
|
|
188276
188301
|
});
|
|
188277
188302
|
program.command("deploy").description("Build all presentations into a static deployable site").option("-o, --output <dir>", "Output directory for the deploy package").option("--base <path>", "Base path for the deployed site (default: /)").action(async (options) => {
|
package/dist/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "supaslidev",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "CLI toolkit for managing Supaslidev presentations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"slidev",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"typescript": "^6.0.3",
|
|
66
66
|
"vitest": "^4.1.5",
|
|
67
67
|
"vue-tsc": "^3.2.7",
|
|
68
|
-
"create-supaslidev": "^0.4.
|
|
68
|
+
"create-supaslidev": "^0.4.2"
|
|
69
69
|
},
|
|
70
70
|
"scripts": {
|
|
71
71
|
"dev": "nuxt dev",
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from 'node:fs';
|
|
13
13
|
import { fileURLToPath } from 'node:url';
|
|
14
14
|
import { findProjectRoot, getPresentations } from '../utils.js';
|
|
15
|
-
import { regeneratePresentationsJson } from '../../shared/presentations.js';
|
|
15
|
+
import { parseFrontmatter, regeneratePresentationsJson } from '../../shared/presentations.js';
|
|
16
16
|
import { optimizeThumbnail } from '../../shared/optimize-thumbnail.js';
|
|
17
17
|
|
|
18
18
|
export interface DeployOptions {
|
|
@@ -84,13 +84,15 @@ function findNuxtBin(
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
export function createVercelConfig(basePath: string, presentations: string[]): string {
|
|
87
|
+
// Use negative lookahead to exclude paths with a dot (file extensions like .js, .css, .png)
|
|
88
|
+
// so that asset requests are served as static files instead of being rewritten to index.html
|
|
87
89
|
const rewrites = presentations.map((id) => ({
|
|
88
|
-
source: `${basePath}presentations/${id}
|
|
90
|
+
source: `${basePath}presentations/${id}/:path((?!.*\\.).*)`,
|
|
89
91
|
destination: `${basePath}presentations/${id}/index.html`,
|
|
90
92
|
}));
|
|
91
93
|
|
|
92
94
|
rewrites.push({
|
|
93
|
-
source: `${basePath}(.*)`,
|
|
95
|
+
source: `${basePath}:path((?!.*\\.).*)`,
|
|
94
96
|
destination: `${basePath}index.html`,
|
|
95
97
|
});
|
|
96
98
|
|
|
@@ -147,7 +149,7 @@ export async function deploy(options: DeployOptions = {}): Promise<void> {
|
|
|
147
149
|
throw new Error('No presentations found in the presentations directory.');
|
|
148
150
|
}
|
|
149
151
|
|
|
150
|
-
const outputDir = resolve(options.output ??
|
|
152
|
+
const outputDir = resolve(projectRoot, options.output ?? 'deploy');
|
|
151
153
|
const resolvedProjectRoot = resolve(projectRoot);
|
|
152
154
|
|
|
153
155
|
// Safety check: prevent deleting directories outside the project root
|
|
@@ -202,16 +204,24 @@ export async function deploy(options: DeployOptions = {}): Promise<void> {
|
|
|
202
204
|
const outputBase = join(thumbnailsDir, id);
|
|
203
205
|
const targetFile = join(thumbnailsDir, `${id}.png`);
|
|
204
206
|
|
|
205
|
-
|
|
207
|
+
// Detect dark mode from frontmatter
|
|
208
|
+
const slidesPath = join(presentationDir, 'slides.md');
|
|
209
|
+
const frontmatter = existsSync(slidesPath)
|
|
210
|
+
? parseFrontmatter(readFileSync(slidesPath, 'utf-8'))
|
|
211
|
+
: {};
|
|
212
|
+
const useDark = frontmatter.colorSchema === 'dark';
|
|
213
|
+
|
|
214
|
+
console.log(` Thumbnail: ${id}${useDark ? ' (dark mode)' : ''}`);
|
|
215
|
+
|
|
216
|
+
const exportArgs = ['export', '--format', 'png', '--range', '1', '--output', outputBase];
|
|
217
|
+
if (useDark) {
|
|
218
|
+
exportArgs.push('--dark');
|
|
219
|
+
}
|
|
206
220
|
|
|
207
221
|
try {
|
|
208
|
-
await runCommand(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
{
|
|
212
|
-
cwd: presentationDir,
|
|
213
|
-
},
|
|
214
|
-
);
|
|
222
|
+
await runCommand(slidevBin, exportArgs, {
|
|
223
|
+
cwd: presentationDir,
|
|
224
|
+
});
|
|
215
225
|
|
|
216
226
|
// Slidev exports into a directory <output>/<n>.png — move to <output>.png
|
|
217
227
|
if (!existsSync(targetFile) && existsSync(outputBase)) {
|
|
@@ -244,6 +254,7 @@ export async function deploy(options: DeployOptions = {}): Promise<void> {
|
|
|
244
254
|
const nuxtEnv: Record<string, string | undefined> = {
|
|
245
255
|
...process.env,
|
|
246
256
|
NODE_ENV: 'production',
|
|
257
|
+
NITRO_PRESET: process.env.NITRO_PRESET ?? 'static',
|
|
247
258
|
SUPASLIDEV_PROJECT_ROOT: projectRoot,
|
|
248
259
|
SUPASLIDEV_PRESENTATIONS_DIR: presentationsDir,
|
|
249
260
|
NUXT_PUBLIC_DEPLOY_MODE: 'true',
|
|
@@ -327,6 +338,24 @@ export async function deploy(options: DeployOptions = {}): Promise<void> {
|
|
|
327
338
|
writeFileSync(join(outputDir, 'netlify.toml'), createNetlifyConfig(basePath, presentations));
|
|
328
339
|
writeFileSync(join(outputDir, 'package.json'), createDeployPackageJson());
|
|
329
340
|
|
|
341
|
+
// Generate root vercel.json for build-from-repo workflow if it doesn't exist
|
|
342
|
+
const rootVercelJson = join(projectRoot, 'vercel.json');
|
|
343
|
+
if (!existsSync(rootVercelJson)) {
|
|
344
|
+
const pm = existsSync(join(projectRoot, 'pnpm-lock.yaml'))
|
|
345
|
+
? 'pnpm'
|
|
346
|
+
: existsSync(join(projectRoot, 'yarn.lock'))
|
|
347
|
+
? 'yarn'
|
|
348
|
+
: 'npm';
|
|
349
|
+
const vercelConfig = {
|
|
350
|
+
framework: null,
|
|
351
|
+
installCommand: `${pm} install`,
|
|
352
|
+
buildCommand: 'npx supaslidev deploy --output dist',
|
|
353
|
+
outputDirectory: 'dist',
|
|
354
|
+
};
|
|
355
|
+
writeFileSync(rootVercelJson, JSON.stringify(vercelConfig, null, 2) + '\n');
|
|
356
|
+
console.log(' Generated vercel.json in project root for Vercel deployment.\n');
|
|
357
|
+
}
|
|
358
|
+
|
|
330
359
|
console.log('='.repeat(50));
|
|
331
360
|
console.log(' Deploy package ready!');
|
|
332
361
|
console.log('='.repeat(50));
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
|
-
import { existsSync, mkdirSync, readdirSync, renameSync } from 'node:fs';
|
|
3
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync } from 'node:fs';
|
|
4
4
|
import { findProjectRoot, getPresentations, printAvailablePresentations } from '../utils.js';
|
|
5
5
|
import { optimizeThumbnail } from '../../shared/optimize-thumbnail.js';
|
|
6
|
+
import { parseFrontmatter } from '../../shared/presentations.js';
|
|
6
7
|
|
|
7
8
|
export interface ThumbnailOptions {
|
|
8
9
|
output?: string;
|
|
10
|
+
dark?: boolean;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export async function thumbnail(name: string, options: ThumbnailOptions = {}): Promise<void> {
|
|
@@ -40,15 +42,26 @@ export async function thumbnail(name: string, options: ThumbnailOptions = {}): P
|
|
|
40
42
|
|
|
41
43
|
const slidevBin = join(presentationDir, 'node_modules', '.bin', 'slidev');
|
|
42
44
|
|
|
45
|
+
// Auto-detect dark mode from frontmatter unless explicitly set
|
|
46
|
+
let useDark = options.dark ?? false;
|
|
47
|
+
if (options.dark === undefined) {
|
|
48
|
+
const slidesPath = join(presentationDir, 'slides.md');
|
|
49
|
+
if (existsSync(slidesPath)) {
|
|
50
|
+
const frontmatter = parseFrontmatter(readFileSync(slidesPath, 'utf-8'));
|
|
51
|
+
useDark = frontmatter.colorSchema === 'dark';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const exportArgs = ['export', '--format', 'png', '--range', '1', '--output', outputPath];
|
|
56
|
+
if (useDark) {
|
|
57
|
+
exportArgs.push('--dark');
|
|
58
|
+
}
|
|
59
|
+
|
|
43
60
|
await new Promise<void>((resolve) => {
|
|
44
|
-
const slidev = spawn(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
cwd: presentationDir,
|
|
49
|
-
stdio: 'inherit',
|
|
50
|
-
},
|
|
51
|
-
);
|
|
61
|
+
const slidev = spawn(slidevBin, exportArgs, {
|
|
62
|
+
cwd: presentationDir,
|
|
63
|
+
stdio: 'inherit',
|
|
64
|
+
});
|
|
52
65
|
|
|
53
66
|
slidev.on('error', (err) => {
|
|
54
67
|
console.error(`Failed to generate thumbnail: ${err.message}`);
|
package/src/cli/index.ts
CHANGED
|
@@ -63,7 +63,8 @@ program
|
|
|
63
63
|
.description('Generate a PNG thumbnail of the first slide')
|
|
64
64
|
.argument('<name>', 'Name of the presentation')
|
|
65
65
|
.option('-o, --output <path>', 'Output path for the thumbnail (without extension)')
|
|
66
|
-
.
|
|
66
|
+
.option('--dark', 'Export as dark theme (auto-detected from colorSchema if not set)')
|
|
67
|
+
.action(async (name: string, options: { output?: string; dark?: boolean }) => {
|
|
67
68
|
await thumbnail(name, options);
|
|
68
69
|
});
|
|
69
70
|
|
|
@@ -93,11 +93,14 @@ export function regeneratePresentationsJson(
|
|
|
93
93
|
const content = readFileSync(slidesPath, 'utf-8');
|
|
94
94
|
const frontmatter = parseFrontmatter(content);
|
|
95
95
|
|
|
96
|
+
const colorSchema = frontmatter.colorSchema as Presentation['colorSchema'];
|
|
97
|
+
|
|
96
98
|
const presentation: Presentation = {
|
|
97
99
|
id: name,
|
|
98
100
|
title: frontmatter.title || name,
|
|
99
101
|
description: extractDescription(frontmatter.info) || '',
|
|
100
102
|
theme: frontmatter.theme || 'default',
|
|
103
|
+
colorSchema: colorSchema || '',
|
|
101
104
|
background: frontmatter.background || '',
|
|
102
105
|
duration: frontmatter.duration || '',
|
|
103
106
|
};
|