orz-slides 0.2.0 → 0.4.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/dist/browser-entry.d.ts +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +53 -113
- package/dist/layout.d.ts +15 -0
- package/dist/lib.d.ts +43 -0
- package/dist/lib.js +189 -0
- package/dist/orz-slides.browser.js +69 -73
- package/dist/render-slide.d.ts +18 -0
- package/dist/slide-parser.d.ts +15 -0
- package/dist/template.d.ts +76 -0
- package/dist/types.d.ts +127 -0
- package/package.json +10 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
CHANGED
|
@@ -12,64 +12,19 @@
|
|
|
12
12
|
* --inline embed the engine bundle + theme CSS in the file (default)
|
|
13
13
|
* --cdn reference the engine + theme from jsDelivr (small files)
|
|
14
14
|
* --title <text> document <title> (fallback; deck `title:` wins)
|
|
15
|
+
*
|
|
16
|
+
* The inline path (the default) is shared with the programmatic library entry
|
|
17
|
+
* `buildSlidesHtml` (src/lib.ts) — there is ONE composition path. The CDN path
|
|
18
|
+
* lives here.
|
|
15
19
|
*/
|
|
16
|
-
import { readFileSync, writeFileSync
|
|
20
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
17
21
|
import { basename, extname, dirname, resolve, join } from 'node:path';
|
|
18
|
-
import { fileURLToPath } from 'node:url';
|
|
19
|
-
import { createRequire } from 'node:module';
|
|
20
22
|
import { randomUUID } from 'node:crypto';
|
|
21
23
|
import { getBrowserRuntimeScript } from 'orz-markdown/runtime';
|
|
22
24
|
import { PREVIEW_CDN } from 'orz-markdown/preview-frame';
|
|
23
25
|
import { parseDeck } from './slide-parser.js';
|
|
24
26
|
import { buildHtml } from './template.js';
|
|
25
|
-
|
|
26
|
-
const THEME_DEFS = [
|
|
27
|
-
{ id: 'paper', name: 'Paper', scheme: 'light' },
|
|
28
|
-
{ id: 'architect', name: 'Architect', scheme: 'light' },
|
|
29
|
-
{ id: 'executive', name: 'Executive', scheme: 'light' },
|
|
30
|
-
{ id: 'sage', name: 'Sage', scheme: 'light' },
|
|
31
|
-
{ id: 'poppy', name: 'Poppy', scheme: 'light' },
|
|
32
|
-
{ id: 'neon', name: 'Neon', scheme: 'dark' },
|
|
33
|
-
{ id: 'chalk', name: 'Chalk', scheme: 'dark' },
|
|
34
|
-
];
|
|
35
|
-
const require = createRequire(import.meta.url);
|
|
36
|
-
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
37
|
-
function pkgVersion(name, fallback = '0.0.0') {
|
|
38
|
-
try {
|
|
39
|
-
let dir = dirname(require.resolve(name));
|
|
40
|
-
while (!existsSync(join(dir, 'package.json')))
|
|
41
|
-
dir = dirname(dir);
|
|
42
|
-
return JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).version || fallback;
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
return fallback;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
/** orz-slides' own version — pins the engine bundle + theme CDN + version check. */
|
|
49
|
-
function selfVersion() {
|
|
50
|
-
for (const p of [join(HERE, '..', 'package.json'), join(HERE, '..', '..', 'package.json')]) {
|
|
51
|
-
try {
|
|
52
|
-
const j = JSON.parse(readFileSync(p, 'utf8'));
|
|
53
|
-
if (j.name === 'orz-slides' && j.version)
|
|
54
|
-
return j.version;
|
|
55
|
-
}
|
|
56
|
-
catch { /* keep looking */ }
|
|
57
|
-
}
|
|
58
|
-
return '0.0.0';
|
|
59
|
-
}
|
|
60
|
-
/** assets/ sits next to dist/ when published, and next to src/ in dev. */
|
|
61
|
-
function findAsset(rel) {
|
|
62
|
-
for (const p of [join(HERE, '..', 'assets', rel), join(HERE, '..', '..', 'assets', rel)]) {
|
|
63
|
-
if (existsSync(p))
|
|
64
|
-
return p;
|
|
65
|
-
}
|
|
66
|
-
throw new Error(`asset not found: ${rel}`);
|
|
67
|
-
}
|
|
68
|
-
/** A theme's CSS without its `@import url('./base.css')` (base is inlined once). */
|
|
69
|
-
function themeOnly(id) {
|
|
70
|
-
const css = readFileSync(findAsset(`themes/theme-${id}.css`), 'utf8');
|
|
71
|
-
return css.replace(/@import\s+url\(\s*['"]?\.\/base\.css['"]?\s*\)\s*;/, '');
|
|
72
|
-
}
|
|
27
|
+
import { THEME_DEFS, selfVersion, findAsset, pkgVersion, buildSlidesHtmlWithDocId, } from './lib.js';
|
|
73
28
|
function parseArgs(argv) {
|
|
74
29
|
const a = { delivery: 'inline' };
|
|
75
30
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -89,74 +44,26 @@ function parseArgs(argv) {
|
|
|
89
44
|
}
|
|
90
45
|
return a;
|
|
91
46
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
const
|
|
99
|
-
const source = readFileSync(inputPath, 'utf8');
|
|
100
|
-
const base = basename(inputPath, extname(inputPath)).replace(/\.slides$/, '');
|
|
101
|
-
const outPath = args.out ? resolve(args.out) : join(dirname(inputPath), `${base}.slides.html`);
|
|
102
|
-
// The deck's own config wins; CLI flags are fallbacks.
|
|
103
|
-
const deck = parseDeck(source);
|
|
104
|
-
const ver = selfVersion();
|
|
105
|
-
const themeBase = `https://cdn.jsdelivr.net/npm/orz-slides@${ver}/assets/themes`;
|
|
106
|
-
const themes = THEME_DEFS.map((t) => ({ ...t, href: `${themeBase}/theme-${t.id}.css` }));
|
|
107
|
-
const wanted = deck.config.theme || args.theme || 'paper';
|
|
108
|
-
const defaultTheme = themes.some((t) => t.id === wanted) ? wanted : themes[0].id;
|
|
109
|
-
const ratio = deck.config.ratio || '16:9';
|
|
110
|
-
const title = deck.config.title || args.title || base;
|
|
111
|
-
// Engine + theme delivery.
|
|
112
|
-
let renderer;
|
|
113
|
-
let theme;
|
|
114
|
-
if (args.delivery === 'inline') {
|
|
115
|
-
const bundlePath = [
|
|
116
|
-
join(HERE, 'orz-slides.browser.js'),
|
|
117
|
-
join(HERE, '..', 'dist', 'orz-slides.browser.js'),
|
|
118
|
-
].find(existsSync);
|
|
119
|
-
if (!bundlePath) {
|
|
120
|
-
console.error('Inline mode needs the engine bundle. Run: npm run bundle');
|
|
121
|
-
process.exit(1);
|
|
122
|
-
}
|
|
123
|
-
renderer = { mode: 'inline', js: readFileSync(bundlePath, 'utf8') };
|
|
124
|
-
theme = {
|
|
125
|
-
mode: 'inline',
|
|
126
|
-
base: readFileSync(findAsset('themes/base.css'), 'utf8'),
|
|
127
|
-
themes: THEME_DEFS.map((t) => ({ id: t.id, css: themeOnly(t.id) })),
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
renderer = { mode: 'cdn', src: `https://cdn.jsdelivr.net/npm/orz-slides-browser@${ver}/orz-slides.browser.js` };
|
|
132
|
-
theme = { mode: 'cdn' };
|
|
133
|
-
}
|
|
47
|
+
/** The CDN delivery path (engine + themes referenced from jsDelivr). */
|
|
48
|
+
function buildCdnHtml(source, title, base, docId, ver, themes, defaultTheme, ratio) {
|
|
49
|
+
const renderer = {
|
|
50
|
+
mode: 'cdn',
|
|
51
|
+
src: `https://cdn.jsdelivr.net/npm/orz-slides-browser@${ver}/orz-slides.browser.js`,
|
|
52
|
+
};
|
|
53
|
+
const theme = { mode: 'cdn' };
|
|
134
54
|
const revealVer = pkgVersion('reveal.js', '5.0.4');
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
revealCss = {
|
|
141
|
-
mode: 'inline',
|
|
142
|
-
reset: readFileSync(join(revealDist, 'reset.css'), 'utf8'),
|
|
143
|
-
core: readFileSync(join(revealDist, 'reveal.css'), 'utf8'),
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
revealCss = {
|
|
148
|
-
mode: 'cdn',
|
|
149
|
-
resetUrl: `https://cdn.jsdelivr.net/npm/reveal.js@${revealVer}/dist/reset.css`,
|
|
150
|
-
coreUrl: `https://cdn.jsdelivr.net/npm/reveal.js@${revealVer}/dist/reveal.css`,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
55
|
+
const revealCss = {
|
|
56
|
+
mode: 'cdn',
|
|
57
|
+
resetUrl: `https://cdn.jsdelivr.net/npm/reveal.js@${revealVer}/dist/reset.css`,
|
|
58
|
+
coreUrl: `https://cdn.jsdelivr.net/npm/reveal.js@${revealVer}/dist/reveal.css`,
|
|
59
|
+
};
|
|
153
60
|
const appJs = readFileSync(findAsset('app.js'), 'utf8');
|
|
154
61
|
const CM = 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16';
|
|
155
|
-
|
|
62
|
+
return buildHtml({
|
|
156
63
|
source,
|
|
157
64
|
title,
|
|
158
65
|
filename: base,
|
|
159
|
-
docId
|
|
66
|
+
docId,
|
|
160
67
|
rendererVersion: ver,
|
|
161
68
|
renderer,
|
|
162
69
|
theme,
|
|
@@ -182,6 +89,39 @@ function main() {
|
|
|
182
89
|
chartJs: PREVIEW_CDN.chartJs,
|
|
183
90
|
},
|
|
184
91
|
});
|
|
92
|
+
}
|
|
93
|
+
function main() {
|
|
94
|
+
const args = parseArgs(process.argv.slice(2));
|
|
95
|
+
if (!args.input) {
|
|
96
|
+
console.error('Usage: orz-slides <input.md> [-o out] [--theme name] [--inline|--cdn]');
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
const inputPath = resolve(args.input);
|
|
100
|
+
const source = readFileSync(inputPath, 'utf8');
|
|
101
|
+
const base = basename(inputPath, extname(inputPath)).replace(/\.slides$/, '');
|
|
102
|
+
const outPath = args.out ? resolve(args.out) : join(dirname(inputPath), `${base}.slides.html`);
|
|
103
|
+
const deck = parseDeck(source);
|
|
104
|
+
const docId = randomUUID();
|
|
105
|
+
// Resolve the effective (validated) theme once, for the log line and CDN path.
|
|
106
|
+
const wanted = deck.config.theme || args.theme || 'paper';
|
|
107
|
+
const defaultTheme = THEME_DEFS.some((t) => t.id === wanted) ? wanted : THEME_DEFS[0].id;
|
|
108
|
+
let html;
|
|
109
|
+
if (args.delivery === 'inline') {
|
|
110
|
+
// Shared inline composition — the library and the CLI produce byte-identical
|
|
111
|
+
// output for the same source (modulo docId). The deck-config precedence and
|
|
112
|
+
// the 'Untitled' fallbacks live in lib.ts; the CLI passes its filename-based
|
|
113
|
+
// title as the fallback so the deck's own title still wins.
|
|
114
|
+
html = buildSlidesHtmlWithDocId({ markdown: source, title: args.title ?? base, theme: args.theme }, docId);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// The deck's own config wins; CLI flags are fallbacks.
|
|
118
|
+
const ver = selfVersion();
|
|
119
|
+
const themeBase = `https://cdn.jsdelivr.net/npm/orz-slides@${ver}/assets/themes`;
|
|
120
|
+
const themes = THEME_DEFS.map((t) => ({ ...t, href: `${themeBase}/theme-${t.id}.css` }));
|
|
121
|
+
const ratio = deck.config.ratio || '16:9';
|
|
122
|
+
const title = deck.config.title || args.title || base;
|
|
123
|
+
html = buildCdnHtml(source, title, base, docId, ver, themes, defaultTheme, ratio);
|
|
124
|
+
}
|
|
185
125
|
writeFileSync(outPath, html, 'utf8');
|
|
186
126
|
console.log(`Wrote ${outPath} (${args.delivery}, theme: ${defaultTheme}, ${deck.slides.length} slides)`);
|
|
187
127
|
}
|
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WP2 — Layout engine. Layout tree → nested CSS-grid DOM.
|
|
3
|
+
*
|
|
4
|
+
* Takes a fully-expanded `LayoutNode` (the parser has already expanded any
|
|
5
|
+
* preset alias), so this module depends only on ./types — nothing else.
|
|
6
|
+
* Pure string building; no DOM API.
|
|
7
|
+
*
|
|
8
|
+
* See BUILD-PLAN.md WP2 and docs/dom-contract.md ("Layout grid (WP2 output)").
|
|
9
|
+
*/
|
|
10
|
+
import type { LayoutNode, GridRender } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Render a layout tree to nested grid DOM with empty region cells.
|
|
13
|
+
* Returns the inner HTML for `.orz-content` and the region names in order.
|
|
14
|
+
*/
|
|
15
|
+
export declare function renderLayout(node: LayoutNode): GridRender;
|
package/dist/lib.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type ThemeEntry } from './template.js';
|
|
2
|
+
/** The seven shipped slide themes (served from the orz-slides package on CDN). */
|
|
3
|
+
export declare const THEME_DEFS: Array<Omit<ThemeEntry, 'href'>>;
|
|
4
|
+
export declare function pkgVersion(name: string, fallback?: string): string;
|
|
5
|
+
/** orz-slides' own version — pins the engine bundle + theme CDN + version check. */
|
|
6
|
+
export declare function selfVersion(): string;
|
|
7
|
+
/** assets/ sits next to dist/ when published, and next to src/ in dev. */
|
|
8
|
+
export declare function findAsset(rel: string): string;
|
|
9
|
+
/** A theme's CSS without its `@import url('./base.css')` (base is inlined once). */
|
|
10
|
+
export declare function themeOnly(id: string): string;
|
|
11
|
+
export interface BuildSlidesOptions {
|
|
12
|
+
/** The deck source (orz-markdown + slide layout syntax). */
|
|
13
|
+
markdown: string;
|
|
14
|
+
/** Document `<title>` fallback; the deck's own `title:` wins. */
|
|
15
|
+
title?: string;
|
|
16
|
+
/** Theme id fallback; the deck's own `theme:` wins. Validated against THEME_DEFS. */
|
|
17
|
+
theme?: string;
|
|
18
|
+
/** Renderer + theme + reveal CSS delivery: `inline` (default, offline) or
|
|
19
|
+
* `cdn` (small file — engine, themes, and reveal.css load from jsDelivr at
|
|
20
|
+
* view time; requires orz-slides-browser to be published at this version). */
|
|
21
|
+
delivery?: 'inline' | 'cdn';
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Shared inline-composition path. Both {@link buildSlidesHtml} and the CLI's
|
|
25
|
+
* `--inline` branch call this; the ONLY difference between them is the `docId`
|
|
26
|
+
* they pass, so with the same `docId` the outputs are byte-identical.
|
|
27
|
+
*
|
|
28
|
+
* @internal — exported for tests / the CLI, not part of the primary API surface.
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildSlidesHtmlWithDocId(opts: BuildSlidesOptions, docId: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Generate a fully self-contained, presentable `.slides.html` document from a
|
|
33
|
+
* deck source string, in-process. Returns the FULL document string.
|
|
34
|
+
*
|
|
35
|
+
* The output is always fully-inline (engine + base/theme CSS + reveal CSS +
|
|
36
|
+
* embedded deck source), byte-identical to the CLI `--inline` output for the
|
|
37
|
+
* same markdown/title/theme (modulo the random docId).
|
|
38
|
+
*
|
|
39
|
+
* Deck-config precedence: the deck's own `title:`/`theme:`/`ratio:` always win;
|
|
40
|
+
* `opts.title`/`opts.theme` are fallbacks (title falls back to `'Untitled'`,
|
|
41
|
+
* theme to `'paper'`, validated against THEME_DEFS).
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildSlidesHtml(opts: BuildSlidesOptions): string;
|
package/dist/lib.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* orz-slides — programmatic library entry.
|
|
3
|
+
*
|
|
4
|
+
* Exposes {@link buildSlidesHtml}, which generates a fully self-contained,
|
|
5
|
+
* presentable `.slides.html` document IN-PROCESS from a deck source string
|
|
6
|
+
* (orz-markdown + the slide layout syntax) — no CLI, no shelling out, no
|
|
7
|
+
* filesystem input file.
|
|
8
|
+
*
|
|
9
|
+
* The output is ALWAYS fully-inline (inlined engine bundle + inlined base/theme
|
|
10
|
+
* CSS + inlined reveal.js CSS + embedded deck source; no CDN engine/theme pins),
|
|
11
|
+
* byte-identical to the CLI `--inline` path for the same markdown/title/theme
|
|
12
|
+
* (modulo the random docId).
|
|
13
|
+
*
|
|
14
|
+
* This module also owns the shared inline-composition helpers (`selfVersion`,
|
|
15
|
+
* `findAsset`, `themeOnly`, `THEME_DEFS`, reveal.js CSS reading, `pkgVersion`)
|
|
16
|
+
* so there is ONE composition path and the CLI imports them rather than
|
|
17
|
+
* duplicating the logic.
|
|
18
|
+
*
|
|
19
|
+
* Asset resolution is ALWAYS via `import.meta.url` (never `process.cwd()`), so
|
|
20
|
+
* the entry works when consumed from an installed npm package.
|
|
21
|
+
*/
|
|
22
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
23
|
+
import { dirname, join } from 'node:path';
|
|
24
|
+
import { fileURLToPath } from 'node:url';
|
|
25
|
+
import { createRequire } from 'node:module';
|
|
26
|
+
import { randomUUID } from 'node:crypto';
|
|
27
|
+
import { getBrowserRuntimeScript } from 'orz-markdown/runtime';
|
|
28
|
+
import { PREVIEW_CDN } from 'orz-markdown/preview-frame';
|
|
29
|
+
import { parseDeck } from './slide-parser.js';
|
|
30
|
+
import { buildHtml } from './template.js';
|
|
31
|
+
/** The seven shipped slide themes (served from the orz-slides package on CDN). */
|
|
32
|
+
export const THEME_DEFS = [
|
|
33
|
+
{ id: 'paper', name: 'Paper', scheme: 'light' },
|
|
34
|
+
{ id: 'architect', name: 'Architect', scheme: 'light' },
|
|
35
|
+
{ id: 'executive', name: 'Executive', scheme: 'light' },
|
|
36
|
+
{ id: 'sage', name: 'Sage', scheme: 'light' },
|
|
37
|
+
{ id: 'poppy', name: 'Poppy', scheme: 'light' },
|
|
38
|
+
{ id: 'neon', name: 'Neon', scheme: 'dark' },
|
|
39
|
+
{ id: 'chalk', name: 'Chalk', scheme: 'dark' },
|
|
40
|
+
];
|
|
41
|
+
const require = createRequire(import.meta.url);
|
|
42
|
+
// Asset resolution anchors on THIS module's location, never process.cwd().
|
|
43
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
44
|
+
export function pkgVersion(name, fallback = '0.0.0') {
|
|
45
|
+
try {
|
|
46
|
+
let dir = dirname(require.resolve(name));
|
|
47
|
+
while (!existsSync(join(dir, 'package.json')))
|
|
48
|
+
dir = dirname(dir);
|
|
49
|
+
return JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).version || fallback;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return fallback;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** orz-slides' own version — pins the engine bundle + theme CDN + version check. */
|
|
56
|
+
export function selfVersion() {
|
|
57
|
+
for (const p of [join(HERE, '..', 'package.json'), join(HERE, '..', '..', 'package.json')]) {
|
|
58
|
+
try {
|
|
59
|
+
const j = JSON.parse(readFileSync(p, 'utf8'));
|
|
60
|
+
if (j.name === 'orz-slides' && j.version)
|
|
61
|
+
return j.version;
|
|
62
|
+
}
|
|
63
|
+
catch { /* keep looking */ }
|
|
64
|
+
}
|
|
65
|
+
return '0.0.0';
|
|
66
|
+
}
|
|
67
|
+
/** assets/ sits next to dist/ when published, and next to src/ in dev. */
|
|
68
|
+
export function findAsset(rel) {
|
|
69
|
+
for (const p of [join(HERE, '..', 'assets', rel), join(HERE, '..', '..', 'assets', rel)]) {
|
|
70
|
+
if (existsSync(p))
|
|
71
|
+
return p;
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`asset not found: ${rel}`);
|
|
74
|
+
}
|
|
75
|
+
/** A theme's CSS without its `@import url('./base.css')` (base is inlined once). */
|
|
76
|
+
export function themeOnly(id) {
|
|
77
|
+
const css = readFileSync(findAsset(`themes/theme-${id}.css`), 'utf8');
|
|
78
|
+
return css.replace(/@import\s+url\(\s*['"]?\.\/base\.css['"]?\s*\)\s*;/, '');
|
|
79
|
+
}
|
|
80
|
+
/** The inlined engine bundle (dist/orz-slides.browser.js), read from disk. */
|
|
81
|
+
function readEngineBundle() {
|
|
82
|
+
const bundlePath = [
|
|
83
|
+
join(HERE, 'orz-slides.browser.js'),
|
|
84
|
+
join(HERE, '..', 'dist', 'orz-slides.browser.js'),
|
|
85
|
+
].find(existsSync);
|
|
86
|
+
if (!bundlePath) {
|
|
87
|
+
throw new Error('Inline mode needs the engine bundle. Run: npm run bundle');
|
|
88
|
+
}
|
|
89
|
+
return readFileSync(bundlePath, 'utf8');
|
|
90
|
+
}
|
|
91
|
+
/** reveal.js reset.css + reveal.css (both contain only data: URIs — offline-safe). */
|
|
92
|
+
function readRevealCss() {
|
|
93
|
+
const revealDist = dirname(require.resolve('reveal.js'));
|
|
94
|
+
return {
|
|
95
|
+
reset: readFileSync(join(revealDist, 'reset.css'), 'utf8'),
|
|
96
|
+
core: readFileSync(join(revealDist, 'reveal.css'), 'utf8'),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Shared inline-composition path. Both {@link buildSlidesHtml} and the CLI's
|
|
101
|
+
* `--inline` branch call this; the ONLY difference between them is the `docId`
|
|
102
|
+
* they pass, so with the same `docId` the outputs are byte-identical.
|
|
103
|
+
*
|
|
104
|
+
* @internal — exported for tests / the CLI, not part of the primary API surface.
|
|
105
|
+
*/
|
|
106
|
+
export function buildSlidesHtmlWithDocId(opts, docId) {
|
|
107
|
+
// The deck's own config wins; the passed options are fallbacks. The library
|
|
108
|
+
// has no input filename, so 'Untitled' stands in where the CLI used `base`.
|
|
109
|
+
const deck = parseDeck(opts.markdown);
|
|
110
|
+
const ver = selfVersion();
|
|
111
|
+
const themeBase = `https://cdn.jsdelivr.net/npm/orz-slides@${ver}/assets/themes`;
|
|
112
|
+
const themes = THEME_DEFS.map((t) => ({ ...t, href: `${themeBase}/theme-${t.id}.css` }));
|
|
113
|
+
const wanted = deck.config.theme || opts.theme || 'paper';
|
|
114
|
+
const defaultTheme = themes.some((t) => t.id === wanted) ? wanted : themes[0].id;
|
|
115
|
+
const ratio = deck.config.ratio || '16:9';
|
|
116
|
+
const title = deck.config.title || opts.title || 'Untitled';
|
|
117
|
+
// Engine + theme + reveal CSS delivery: inline (default, offline) or CDN.
|
|
118
|
+
const cdn = opts.delivery === 'cdn';
|
|
119
|
+
const renderer = cdn
|
|
120
|
+
? { mode: 'cdn', src: `https://cdn.jsdelivr.net/npm/orz-slides-browser@${ver}/orz-slides.browser.js` }
|
|
121
|
+
: { mode: 'inline', js: readEngineBundle() };
|
|
122
|
+
const theme = cdn
|
|
123
|
+
? { mode: 'cdn' }
|
|
124
|
+
: {
|
|
125
|
+
mode: 'inline',
|
|
126
|
+
base: readFileSync(findAsset('themes/base.css'), 'utf8'),
|
|
127
|
+
themes: THEME_DEFS.map((t) => ({ id: t.id, css: themeOnly(t.id) })),
|
|
128
|
+
};
|
|
129
|
+
let revealCss;
|
|
130
|
+
if (cdn) {
|
|
131
|
+
const revealVer = pkgVersion('reveal.js', '5.0.4');
|
|
132
|
+
revealCss = {
|
|
133
|
+
mode: 'cdn',
|
|
134
|
+
resetUrl: `https://cdn.jsdelivr.net/npm/reveal.js@${revealVer}/dist/reset.css`,
|
|
135
|
+
coreUrl: `https://cdn.jsdelivr.net/npm/reveal.js@${revealVer}/dist/reveal.css`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
const reveal = readRevealCss();
|
|
140
|
+
revealCss = { mode: 'inline', reset: reveal.reset, core: reveal.core };
|
|
141
|
+
}
|
|
142
|
+
const appJs = readFileSync(findAsset('app.js'), 'utf8');
|
|
143
|
+
const CM = 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16';
|
|
144
|
+
return buildHtml({
|
|
145
|
+
source: opts.markdown,
|
|
146
|
+
title,
|
|
147
|
+
filename: 'Untitled',
|
|
148
|
+
docId,
|
|
149
|
+
rendererVersion: ver,
|
|
150
|
+
renderer,
|
|
151
|
+
theme,
|
|
152
|
+
defaultTheme,
|
|
153
|
+
themes,
|
|
154
|
+
ratio,
|
|
155
|
+
versionManifest: 'https://data.jsdelivr.com/v1/packages/npm/orz-slides-browser/resolved',
|
|
156
|
+
appJs,
|
|
157
|
+
runtime: getBrowserRuntimeScript(),
|
|
158
|
+
editorLibs: {
|
|
159
|
+
codemirrorCss: `${CM}/codemirror.min.css`,
|
|
160
|
+
codemirrorLightThemeCss: `${CM}/theme/eclipse.min.css`,
|
|
161
|
+
codemirrorDarkThemeCss: `${CM}/theme/material-darker.min.css`,
|
|
162
|
+
codemirrorJs: `${CM}/codemirror.min.js`,
|
|
163
|
+
codemirrorMarkdownJs: `${CM}/mode/markdown/markdown.min.js`,
|
|
164
|
+
codemirrorContinuelistJs: `${CM}/addon/edit/continuelist.min.js`,
|
|
165
|
+
},
|
|
166
|
+
revealCss,
|
|
167
|
+
cdn: {
|
|
168
|
+
katexCss: PREVIEW_CDN.katexCss,
|
|
169
|
+
mermaidJs: PREVIEW_CDN.mermaidJs,
|
|
170
|
+
smilesJs: PREVIEW_CDN.smilesJs,
|
|
171
|
+
chartJs: PREVIEW_CDN.chartJs,
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Generate a fully self-contained, presentable `.slides.html` document from a
|
|
177
|
+
* deck source string, in-process. Returns the FULL document string.
|
|
178
|
+
*
|
|
179
|
+
* The output is always fully-inline (engine + base/theme CSS + reveal CSS +
|
|
180
|
+
* embedded deck source), byte-identical to the CLI `--inline` output for the
|
|
181
|
+
* same markdown/title/theme (modulo the random docId).
|
|
182
|
+
*
|
|
183
|
+
* Deck-config precedence: the deck's own `title:`/`theme:`/`ratio:` always win;
|
|
184
|
+
* `opts.title`/`opts.theme` are fallbacks (title falls back to `'Untitled'`,
|
|
185
|
+
* theme to `'paper'`, validated against THEME_DEFS).
|
|
186
|
+
*/
|
|
187
|
+
export function buildSlidesHtml(opts) {
|
|
188
|
+
return buildSlidesHtmlWithDocId(opts, randomUUID());
|
|
189
|
+
}
|