@classic-homes/slides 0.2.0 → 0.3.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 +74 -25
- package/dist/{chunk-CKVKX2ZD.js → chunk-2IPLZ3SA.js} +37 -7
- package/dist/chunk-2IPLZ3SA.js.map +1 -0
- package/dist/{chunk-TM3TNVHB.js → chunk-GXGDPBAR.js} +2717 -493
- package/dist/chunk-GXGDPBAR.js.map +1 -0
- package/dist/chunk-YI7A4EWX.js +107 -0
- package/dist/chunk-YI7A4EWX.js.map +1 -0
- package/dist/cli.js +15 -5
- package/dist/cli.js.map +1 -1
- package/dist/echarts-render-2QVSBZ6V.js +50 -0
- package/dist/echarts-render-2QVSBZ6V.js.map +1 -0
- package/dist/index.d.ts +149 -4
- package/dist/index.js +72 -133
- package/dist/index.js.map +1 -1
- package/dist/{mcp-5R6YD3QW.js → mcp-PUA45IS7.js} +17 -14
- package/dist/mcp-PUA45IS7.js.map +1 -0
- package/dist/node.d.ts +4 -2
- package/dist/node.js +2 -2
- package/dist/render-DcyKuBRD.d.ts +580 -0
- package/package.json +13 -3
- package/dist/chunk-CKVKX2ZD.js.map +0 -1
- package/dist/chunk-TM3TNVHB.js.map +0 -1
- package/dist/chunk-TXNQKBWJ.js +0 -69
- package/dist/chunk-TXNQKBWJ.js.map +0 -1
- package/dist/chunk-VONVGYRL.js +0 -52
- package/dist/chunk-VONVGYRL.js.map +0 -1
- package/dist/mcp-5R6YD3QW.js.map +0 -1
- package/dist/render-CZ4g2fa9.d.ts +0 -136
package/README.md
CHANGED
|
@@ -63,38 +63,82 @@ Inline text supports `**bold**`, `*highlight*` (brand accent), `` `code` `` and
|
|
|
63
63
|
Run `classic-slides layouts` for the list, `classic-slides layouts <name>` for
|
|
64
64
|
every field plus an example.
|
|
65
65
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
| `title`
|
|
69
|
-
|
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `split`
|
|
73
|
-
|
|
|
74
|
-
| `stats` | 2–6 numbers worth remembering |
|
|
75
|
-
| `comparison` | 2–3 columns side by side |
|
|
76
|
-
| `journey` | Numbered agenda map (uses `journey.steps`) |
|
|
77
|
-
| `photos` | A grid of photos: team, products, homes |
|
|
78
|
-
| `image` | One big image or diagram |
|
|
79
|
-
| `walkthrough` | Ordered stages, one slide each with a progress rail |
|
|
80
|
-
| `quote` | A testimonial or pull quote |
|
|
81
|
-
| `qr` | Send people to a URL with a scannable code |
|
|
82
|
-
| `contacts` | Who to call |
|
|
66
|
+
| Group | Layouts |
|
|
67
|
+
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
68
|
+
| Openers & dividers | `title`, `section`, `statement`, `journey` |
|
|
69
|
+
| Text | `bullets`, `cards`, `comparison`, `quote` |
|
|
70
|
+
| Data | `stats` (with trends + sparklines), `chart`, `table` |
|
|
71
|
+
| Diagrams | `flow`, `timeline`, `cycle`, `hierarchy`, `matrix`, `tiers` (funnel / pyramid) |
|
|
72
|
+
| Media | `split`, `photos`, `image` (with numbered hotspots), `compare` (before/after), `walkthrough`, `video` (YouTube/Vimeo), `embed` (any https page) |
|
|
73
|
+
| People & places | `qr`, `contacts` |
|
|
83
74
|
|
|
84
75
|
Every slide also accepts `track` (value/red, build/teal, neutral/navy),
|
|
85
|
-
`background` (paper or a solid brand colour), `
|
|
86
|
-
decks with `journey.steps` — `step`,
|
|
76
|
+
`background` (paper or a solid brand colour), `backgroundImage` + `overlay`,
|
|
77
|
+
`notes`, `time`, `id`, `hidden`, and — in decks with `journey.steps` — `step`,
|
|
78
|
+
`stepDone` and `showJourney`. `bullets`, `cards`, `flow` and `timeline` take
|
|
79
|
+
`build: true` to reveal one item per click.
|
|
87
80
|
|
|
88
|
-
|
|
89
|
-
|
|
81
|
+
### Charts
|
|
82
|
+
|
|
83
|
+
```yaml
|
|
84
|
+
- layout: chart
|
|
85
|
+
title: Closings *doubled* since spring
|
|
86
|
+
chart:
|
|
87
|
+
type: column # bar, stacked-column, stacked-bar, line, area, pie, donut, funnel, gauge, scatter, radar
|
|
88
|
+
labels: [Q1, Q2, Q3, Q4]
|
|
89
|
+
series: [{ name: Closings, values: [42, 61, 88, 94] }]
|
|
90
|
+
unit: homes
|
|
91
|
+
highlight: Q4
|
|
92
|
+
insights: [Q4 best quarter on record]
|
|
93
|
+
source: Sales ops
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Charts are rendered to static SVG with ECharts (server-side rendering, themed
|
|
97
|
+
from `@classic-homes/charts-core`), so they work offline and in print. ECharts
|
|
98
|
+
is loaded only when a deck has charts.
|
|
99
|
+
|
|
100
|
+
### Video and embeds
|
|
101
|
+
|
|
102
|
+
`video` takes YouTube/Vimeo links (privacy-enhanced players); `embed` takes any
|
|
103
|
+
https page (maps, dashboards, 3D tours, forms) in a sandboxed frame. Both load
|
|
104
|
+
only while their slide is shown, and fall back to a poster/screenshot with a QR
|
|
105
|
+
code offline, in print and in PDF.
|
|
106
|
+
|
|
107
|
+
## Brand profiles and deck settings
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
brand:
|
|
111
|
+
profile: pentrust # admin-managed profile; default classic-homes
|
|
112
|
+
name: PenTrust Lending # optional overrides: name, tagline, logo, logoOnDark, favicon, footer
|
|
113
|
+
settings:
|
|
114
|
+
slideNumbers: true
|
|
115
|
+
logo: all # title | all | none
|
|
116
|
+
confidential: Internal
|
|
117
|
+
autoAdvance: 15 # kiosk mode (also ?kiosk=15 on the URL)
|
|
118
|
+
loop: true
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Profiles (`BrandProfile`) carry name, logos, favicon, footer and an optional
|
|
122
|
+
palette; `validateBrandProfile()` enforces WCAG AA contrast. Pass them to
|
|
123
|
+
`renderDeck(deck, { brands })` / `validateDeck(deck, { brands })`. Authors can
|
|
124
|
+
override words and images, never colours.
|
|
125
|
+
|
|
126
|
+
## Presenting
|
|
127
|
+
|
|
128
|
+
Arrow keys / Space advance (and step through reveals) · **N** notes · **P**
|
|
129
|
+
presenter window (current + next slide, notes, timer, clock) · **O** overview ·
|
|
130
|
+
**F** fullscreen · `#slide-7` deep links · `?kiosk=15` loops unattended. Print
|
|
131
|
+
to PDF gives one 16:9 page per slide with media fallbacks.
|
|
90
132
|
|
|
91
133
|
## With an AI agent (MCP)
|
|
92
134
|
|
|
93
135
|
The package ships an MCP server that edits deck files slide by slide and
|
|
94
|
-
validates before every save, so an agent cannot leave a deck broken.
|
|
136
|
+
validates before every save, so an agent cannot leave a deck broken. It needs
|
|
137
|
+
`@modelcontextprotocol/sdk` (an optional peer, so apps that only render decks
|
|
138
|
+
don't install it).
|
|
95
139
|
|
|
96
140
|
```bash
|
|
97
|
-
claude mcp add classic-slides -- npx -y @classic-homes/slides mcp --root ./decks
|
|
141
|
+
claude mcp add classic-slides -- npx -y -p @classic-homes/slides -p @modelcontextprotocol/sdk classic-slides mcp --root ./decks
|
|
98
142
|
```
|
|
99
143
|
|
|
100
144
|
Then ask: _"Build a 10-slide deck in closing-day.yaml for first-time buyers
|
|
@@ -115,8 +159,13 @@ import { buildDeckFile, fileImageResolver } from '@classic-homes/slides/node';
|
|
|
115
159
|
const { html } = await renderDeck(deck, { resolveImage: (src) => lookUp(src) });
|
|
116
160
|
```
|
|
117
161
|
|
|
118
|
-
The core entry has no Node dependencies (it runs in Workers);
|
|
119
|
-
file-based image loading and `buildDeckFile`.
|
|
162
|
+
The core entry has no Node dependencies (it runs in Workers and browsers);
|
|
163
|
+
`/node` adds file-based image loading and `buildDeckFile`. For editors,
|
|
164
|
+
`layoutEditorInfo()` / `deckEditorFields()` describe every field as a widget
|
|
165
|
+
(with `hint`s for chart, grid, url, video-url and point pickers),
|
|
166
|
+
`blankSlide(layout)` gives a valid starting slide, and `renderDeck(deck,
|
|
167
|
+
{ includeHidden: true, initialSlide })` plus the `postMessage` API drive a
|
|
168
|
+
live preview.
|
|
120
169
|
|
|
121
170
|
Rendered HTML embeds the deck source (minus image data), so
|
|
122
171
|
`extractDeckSource(html)` recovers the editable deck.
|
|
@@ -2,11 +2,38 @@ import {
|
|
|
2
2
|
parseDeckSource,
|
|
3
3
|
renderDeck,
|
|
4
4
|
stringifyDeck
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-GXGDPBAR.js";
|
|
6
6
|
|
|
7
7
|
// src/node/index.ts
|
|
8
8
|
import { readFile, stat, writeFile } from "fs/promises";
|
|
9
|
-
import { dirname, extname, isAbsolute, join, resolve } from "path";
|
|
9
|
+
import { dirname as dirname2, extname, isAbsolute, join, resolve as resolve2 } from "path";
|
|
10
|
+
|
|
11
|
+
// src/node/paths.ts
|
|
12
|
+
import { lstatSync, realpathSync } from "fs";
|
|
13
|
+
import { dirname, relative, resolve, sep } from "path";
|
|
14
|
+
function confinedPath(root, path) {
|
|
15
|
+
const canonicalRoot = realpathSync(root);
|
|
16
|
+
const absolute = resolve(path);
|
|
17
|
+
let ancestor = absolute;
|
|
18
|
+
for (; ; ) {
|
|
19
|
+
try {
|
|
20
|
+
const canonical = resolve(realpathSync(ancestor), relative(ancestor, absolute));
|
|
21
|
+
if (canonical !== canonicalRoot && !canonical.startsWith(canonicalRoot + sep)) {
|
|
22
|
+
throw new Error(`Path "${path}" is outside the deck root ${root}.`);
|
|
23
|
+
}
|
|
24
|
+
return canonical;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (error.code !== "ENOENT" || ancestor === dirname(ancestor))
|
|
27
|
+
throw error;
|
|
28
|
+
if (lstatSync(ancestor, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
29
|
+
throw new Error(`Cannot follow dangling symlink "${ancestor}".`);
|
|
30
|
+
}
|
|
31
|
+
ancestor = dirname(ancestor);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/node/index.ts
|
|
10
37
|
var MIME = {
|
|
11
38
|
".jpg": "image/jpeg",
|
|
12
39
|
".jpeg": "image/jpeg",
|
|
@@ -32,7 +59,8 @@ function fileImageResolver(baseDir, options = {}) {
|
|
|
32
59
|
warn(`${src} is ${(buf2.length / 1024).toFixed(0)} KB; consider a smaller copy.`);
|
|
33
60
|
return `data:${type2};base64,${buf2.toString("base64")}`;
|
|
34
61
|
}
|
|
35
|
-
const
|
|
62
|
+
const candidate = isAbsolute(src) ? src : join(baseDir, src);
|
|
63
|
+
const path = options.rootDir ? confinedPath(options.rootDir, candidate) : candidate;
|
|
36
64
|
const type = MIME[extname(path).toLowerCase()];
|
|
37
65
|
if (!type)
|
|
38
66
|
throw new Error(`Unsupported image type for "${src}". Use jpg, png, webp, gif, svg or avif.`);
|
|
@@ -55,22 +83,24 @@ async function saveDeckFile(path, deck) {
|
|
|
55
83
|
await writeFile(path, text);
|
|
56
84
|
}
|
|
57
85
|
async function buildDeckFile(path, options = {}) {
|
|
58
|
-
const abs =
|
|
86
|
+
const abs = options.rootDir ? confinedPath(options.rootDir, resolve2(path)) : resolve2(path);
|
|
59
87
|
const deck = await loadDeckFile(abs);
|
|
60
88
|
const result = await renderDeck(deck, {
|
|
61
89
|
...options,
|
|
62
|
-
resolveImage: fileImageResolver(
|
|
90
|
+
resolveImage: fileImageResolver(dirname2(abs), options)
|
|
63
91
|
});
|
|
64
|
-
const
|
|
92
|
+
const candidate = options.out ? resolve2(options.out) : abs.replace(/\.(ya?ml|json)$/i, "") + ".html";
|
|
93
|
+
const out = options.rootDir ? confinedPath(options.rootDir, candidate) : candidate;
|
|
65
94
|
await writeFile(out, result.html);
|
|
66
95
|
return { ...result, out, bytes: (await stat(out)).size };
|
|
67
96
|
}
|
|
68
97
|
|
|
69
98
|
export {
|
|
99
|
+
confinedPath,
|
|
70
100
|
IMAGE_WARN_BYTES,
|
|
71
101
|
fileImageResolver,
|
|
72
102
|
loadDeckFile,
|
|
73
103
|
saveDeckFile,
|
|
74
104
|
buildDeckFile
|
|
75
105
|
};
|
|
76
|
-
//# sourceMappingURL=chunk-
|
|
106
|
+
//# sourceMappingURL=chunk-2IPLZ3SA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/node/index.ts","../src/node/paths.ts"],"sourcesContent":["/** Node-only helpers: read deck files, inline local images, write HTML. */\nimport { readFile, stat, writeFile } from 'node:fs/promises';\nimport { dirname, extname, isAbsolute, join, resolve } from 'node:path';\nimport { confinedPath } from './paths.js';\nimport { parseDeckSource, stringifyDeck } from '../parse.js';\nimport {\n renderDeck,\n type ImageResolver,\n type RenderOptions,\n type RenderResult,\n} from '../render.js';\n\nconst MIME: Record<string, string> = {\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.png': 'image/png',\n '.webp': 'image/webp',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.avif': 'image/avif',\n};\n\n/** Largest single image we inline without warning. Big photos bloat the deck file. */\nexport const IMAGE_WARN_BYTES = 800 * 1024;\n\nexport interface FileResolverOptions {\n /** Restrict local image reads and build paths to this root (used by the MCP server). */\n rootDir?: string;\n /** Fetch https images and inline them so the deck works offline. Default true. */\n inlineRemote?: boolean;\n onWarning?: (message: string) => void;\n}\n\n/** Resolves image paths relative to the deck file and inlines them as data URIs. */\nexport function fileImageResolver(\n baseDir: string,\n options: FileResolverOptions = {}\n): ImageResolver {\n const warn = options.onWarning ?? (() => {});\n return async (src) => {\n if (src.startsWith('data:')) return src;\n if (/^https?:/.test(src)) {\n if (options.inlineRemote === false) return src;\n const res = await fetch(src);\n if (!res.ok) throw new Error(`Image ${src} returned HTTP ${res.status}`);\n const type = res.headers.get('content-type') ?? 'application/octet-stream';\n const buf = Buffer.from(await res.arrayBuffer());\n if (buf.length > IMAGE_WARN_BYTES)\n warn(`${src} is ${(buf.length / 1024).toFixed(0)} KB; consider a smaller copy.`);\n return `data:${type};base64,${buf.toString('base64')}`;\n }\n const candidate = isAbsolute(src) ? src : join(baseDir, src);\n const path = options.rootDir ? confinedPath(options.rootDir, candidate) : candidate;\n const type = MIME[extname(path).toLowerCase()];\n if (!type)\n throw new Error(`Unsupported image type for \"${src}\". Use jpg, png, webp, gif, svg or avif.`);\n let buf: Buffer;\n try {\n buf = await readFile(path);\n } catch {\n throw new Error(`Image not found: \"${src}\" (looked in ${path})`);\n }\n if (buf.length > IMAGE_WARN_BYTES)\n warn(`${src} is ${(buf.length / 1024).toFixed(0)} KB; consider resizing to ~2000px wide.`);\n return `data:${type};base64,${buf.toString('base64')}`;\n };\n}\n\nexport async function loadDeckFile(path: string): Promise<unknown> {\n return parseDeckSource(await readFile(path, 'utf8'));\n}\n\nexport async function saveDeckFile(path: string, deck: unknown): Promise<void> {\n const text = path.endsWith('.json') ? JSON.stringify(deck, null, 2) + '\\n' : stringifyDeck(deck);\n await writeFile(path, text);\n}\n\nexport interface BuildOptions extends Omit<RenderOptions, 'resolveImage'>, FileResolverOptions {\n out?: string;\n}\n\n/** Renders a deck file to a self-contained HTML file next to it (or at `out`). */\nexport async function buildDeckFile(\n path: string,\n options: BuildOptions = {}\n): Promise<RenderResult & { out: string; bytes: number }> {\n const abs = options.rootDir ? confinedPath(options.rootDir, resolve(path)) : resolve(path);\n const deck = await loadDeckFile(abs);\n const result = await renderDeck(deck, {\n ...options,\n resolveImage: fileImageResolver(dirname(abs), options),\n });\n const candidate = options.out\n ? resolve(options.out)\n : abs.replace(/\\.(ya?ml|json)$/i, '') + '.html';\n const out = options.rootDir ? confinedPath(options.rootDir, candidate) : candidate;\n await writeFile(out, result.html);\n return { ...result, out, bytes: (await stat(out)).size };\n}\n\nexport { renderDeck };\n","/** Canonical containment for existing files and new output files. */\nimport { lstatSync, realpathSync } from 'node:fs';\nimport { dirname, relative, resolve, sep } from 'node:path';\n\nexport function confinedPath(root: string, path: string): string {\n const canonicalRoot = realpathSync(root);\n const absolute = resolve(path);\n let ancestor = absolute;\n for (;;) {\n try {\n const canonical = resolve(realpathSync(ancestor), relative(ancestor, absolute));\n if (canonical !== canonicalRoot && !canonical.startsWith(canonicalRoot + sep)) {\n throw new Error(`Path \"${path}\" is outside the deck root ${root}.`);\n }\n return canonical;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT' || ancestor === dirname(ancestor))\n throw error;\n if (lstatSync(ancestor, { throwIfNoEntry: false })?.isSymbolicLink()) {\n throw new Error(`Cannot follow dangling symlink \"${ancestor}\".`);\n }\n ancestor = dirname(ancestor);\n }\n }\n}\n"],"mappings":"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","names":["dirname","resolve","type","buf","resolve","dirname"]}
|