@classic-homes/slides 0.2.1 → 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/README.md +80 -23
- package/dist/chunk-JFUJ47TP.js +107 -0
- package/dist/chunk-JFUJ47TP.js.map +1 -0
- package/dist/{chunk-MYY5GZC2.js → chunk-L7G3VH7K.js} +37 -7
- package/dist/chunk-L7G3VH7K.js.map +1 -0
- package/dist/{chunk-7FROOJCY.js → chunk-PTTLL6PQ.js} +2503 -300
- package/dist/chunk-PTTLL6PQ.js.map +1 -0
- package/dist/cli.js +4 -4
- package/dist/echarts-render-2QVSBZ6V.js +50 -0
- package/dist/echarts-render-2QVSBZ6V.js.map +1 -0
- package/dist/index.d.ts +154 -4
- package/dist/index.js +66 -12
- package/dist/index.js.map +1 -1
- package/dist/{mcp-DGMQTIQI.js → mcp-UX32IP2J.js} +17 -14
- package/dist/mcp-UX32IP2J.js.map +1 -0
- package/dist/node.d.ts +4 -2
- package/dist/node.js +2 -2
- package/dist/render-CU0sXO2y.d.ts +604 -0
- package/package.json +3 -1
- package/dist/chunk-33EPZMT6.js +0 -69
- package/dist/chunk-33EPZMT6.js.map +0 -1
- package/dist/chunk-7FROOJCY.js.map +0 -1
- package/dist/chunk-MYY5GZC2.js.map +0 -1
- package/dist/chunk-VONVGYRL.js +0 -52
- package/dist/chunk-VONVGYRL.js.map +0 -1
- package/dist/mcp-DGMQTIQI.js.map +0 -1
- package/dist/render-DTz7tLKM.d.ts +0 -149
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const Image: z.ZodEffects<z.ZodObject<{
|
|
4
|
+
src: z.ZodString;
|
|
5
|
+
alt: z.ZodDefault<z.ZodString>;
|
|
6
|
+
fit: z.ZodDefault<z.ZodEnum<["cover", "contain"]>>;
|
|
7
|
+
size: z.ZodDefault<z.ZodEnum<["fill", "natural"]>>;
|
|
8
|
+
focus: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
src: string;
|
|
11
|
+
alt: string;
|
|
12
|
+
fit: "cover" | "contain";
|
|
13
|
+
size: "fill" | "natural";
|
|
14
|
+
focus?: string | undefined;
|
|
15
|
+
}, {
|
|
16
|
+
src: string;
|
|
17
|
+
alt?: string | undefined;
|
|
18
|
+
fit?: "cover" | "contain" | undefined;
|
|
19
|
+
size?: "fill" | "natural" | undefined;
|
|
20
|
+
focus?: string | undefined;
|
|
21
|
+
}>, {
|
|
22
|
+
src: string;
|
|
23
|
+
alt: string;
|
|
24
|
+
fit: "cover" | "contain";
|
|
25
|
+
size: "fill" | "natural";
|
|
26
|
+
focus?: string | undefined;
|
|
27
|
+
}, unknown>;
|
|
28
|
+
type ImageInput = z.input<typeof Image>;
|
|
29
|
+
type ImageValue = z.output<typeof Image>;
|
|
30
|
+
declare const Item: z.ZodEffects<z.ZodObject<{
|
|
31
|
+
text: z.ZodString;
|
|
32
|
+
sub: z.ZodOptional<z.ZodString>;
|
|
33
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
|
+
text: string;
|
|
35
|
+
sub?: string | undefined;
|
|
36
|
+
}, {
|
|
37
|
+
text: string;
|
|
38
|
+
sub?: string | undefined;
|
|
39
|
+
}>, {
|
|
40
|
+
text: string;
|
|
41
|
+
sub?: string | undefined;
|
|
42
|
+
}, unknown>;
|
|
43
|
+
type ItemValue = z.output<typeof Item>;
|
|
44
|
+
|
|
45
|
+
declare const BrandPaletteSchema: z.ZodObject<{
|
|
46
|
+
primary: z.ZodString;
|
|
47
|
+
accent: z.ZodString;
|
|
48
|
+
dark: z.ZodString;
|
|
49
|
+
}, "strict", z.ZodTypeAny, {
|
|
50
|
+
dark: string;
|
|
51
|
+
primary: string;
|
|
52
|
+
accent: string;
|
|
53
|
+
}, {
|
|
54
|
+
dark: string;
|
|
55
|
+
primary: string;
|
|
56
|
+
accent: string;
|
|
57
|
+
}>;
|
|
58
|
+
type BrandPalette = z.infer<typeof BrandPaletteSchema>;
|
|
59
|
+
declare const BrandProfileSchema: z.ZodObject<{
|
|
60
|
+
key: z.ZodString;
|
|
61
|
+
name: z.ZodString;
|
|
62
|
+
tagline: z.ZodOptional<z.ZodString>;
|
|
63
|
+
logo: z.ZodOptional<z.ZodEffects<z.ZodObject<{
|
|
64
|
+
src: z.ZodString;
|
|
65
|
+
alt: z.ZodDefault<z.ZodString>;
|
|
66
|
+
fit: z.ZodDefault<z.ZodEnum<["cover", "contain"]>>;
|
|
67
|
+
size: z.ZodDefault<z.ZodEnum<["fill", "natural"]>>;
|
|
68
|
+
focus: z.ZodOptional<z.ZodString>;
|
|
69
|
+
}, "strip", z.ZodTypeAny, {
|
|
70
|
+
src: string;
|
|
71
|
+
alt: string;
|
|
72
|
+
fit: "cover" | "contain";
|
|
73
|
+
size: "fill" | "natural";
|
|
74
|
+
focus?: string | undefined;
|
|
75
|
+
}, {
|
|
76
|
+
src: string;
|
|
77
|
+
alt?: string | undefined;
|
|
78
|
+
fit?: "cover" | "contain" | undefined;
|
|
79
|
+
size?: "fill" | "natural" | undefined;
|
|
80
|
+
focus?: string | undefined;
|
|
81
|
+
}>, {
|
|
82
|
+
src: string;
|
|
83
|
+
alt: string;
|
|
84
|
+
fit: "cover" | "contain";
|
|
85
|
+
size: "fill" | "natural";
|
|
86
|
+
focus?: string | undefined;
|
|
87
|
+
}, unknown>>;
|
|
88
|
+
logoOnDark: z.ZodOptional<z.ZodEffects<z.ZodObject<{
|
|
89
|
+
src: z.ZodString;
|
|
90
|
+
alt: z.ZodDefault<z.ZodString>;
|
|
91
|
+
fit: z.ZodDefault<z.ZodEnum<["cover", "contain"]>>;
|
|
92
|
+
size: z.ZodDefault<z.ZodEnum<["fill", "natural"]>>;
|
|
93
|
+
focus: z.ZodOptional<z.ZodString>;
|
|
94
|
+
}, "strip", z.ZodTypeAny, {
|
|
95
|
+
src: string;
|
|
96
|
+
alt: string;
|
|
97
|
+
fit: "cover" | "contain";
|
|
98
|
+
size: "fill" | "natural";
|
|
99
|
+
focus?: string | undefined;
|
|
100
|
+
}, {
|
|
101
|
+
src: string;
|
|
102
|
+
alt?: string | undefined;
|
|
103
|
+
fit?: "cover" | "contain" | undefined;
|
|
104
|
+
size?: "fill" | "natural" | undefined;
|
|
105
|
+
focus?: string | undefined;
|
|
106
|
+
}>, {
|
|
107
|
+
src: string;
|
|
108
|
+
alt: string;
|
|
109
|
+
fit: "cover" | "contain";
|
|
110
|
+
size: "fill" | "natural";
|
|
111
|
+
focus?: string | undefined;
|
|
112
|
+
}, unknown>>;
|
|
113
|
+
favicon: z.ZodOptional<z.ZodEffects<z.ZodObject<{
|
|
114
|
+
src: z.ZodString;
|
|
115
|
+
alt: z.ZodDefault<z.ZodString>;
|
|
116
|
+
fit: z.ZodDefault<z.ZodEnum<["cover", "contain"]>>;
|
|
117
|
+
size: z.ZodDefault<z.ZodEnum<["fill", "natural"]>>;
|
|
118
|
+
focus: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, "strip", z.ZodTypeAny, {
|
|
120
|
+
src: string;
|
|
121
|
+
alt: string;
|
|
122
|
+
fit: "cover" | "contain";
|
|
123
|
+
size: "fill" | "natural";
|
|
124
|
+
focus?: string | undefined;
|
|
125
|
+
}, {
|
|
126
|
+
src: string;
|
|
127
|
+
alt?: string | undefined;
|
|
128
|
+
fit?: "cover" | "contain" | undefined;
|
|
129
|
+
size?: "fill" | "natural" | undefined;
|
|
130
|
+
focus?: string | undefined;
|
|
131
|
+
}>, {
|
|
132
|
+
src: string;
|
|
133
|
+
alt: string;
|
|
134
|
+
fit: "cover" | "contain";
|
|
135
|
+
size: "fill" | "natural";
|
|
136
|
+
focus?: string | undefined;
|
|
137
|
+
}, unknown>>;
|
|
138
|
+
palette: z.ZodOptional<z.ZodObject<{
|
|
139
|
+
primary: z.ZodString;
|
|
140
|
+
accent: z.ZodString;
|
|
141
|
+
dark: z.ZodString;
|
|
142
|
+
}, "strict", z.ZodTypeAny, {
|
|
143
|
+
dark: string;
|
|
144
|
+
primary: string;
|
|
145
|
+
accent: string;
|
|
146
|
+
}, {
|
|
147
|
+
dark: string;
|
|
148
|
+
primary: string;
|
|
149
|
+
accent: string;
|
|
150
|
+
}>>;
|
|
151
|
+
footer: z.ZodOptional<z.ZodString>;
|
|
152
|
+
}, "strict", z.ZodTypeAny, {
|
|
153
|
+
key: string;
|
|
154
|
+
name: string;
|
|
155
|
+
tagline?: string | undefined;
|
|
156
|
+
logo?: {
|
|
157
|
+
src: string;
|
|
158
|
+
alt: string;
|
|
159
|
+
fit: "cover" | "contain";
|
|
160
|
+
size: "fill" | "natural";
|
|
161
|
+
focus?: string | undefined;
|
|
162
|
+
} | undefined;
|
|
163
|
+
logoOnDark?: {
|
|
164
|
+
src: string;
|
|
165
|
+
alt: string;
|
|
166
|
+
fit: "cover" | "contain";
|
|
167
|
+
size: "fill" | "natural";
|
|
168
|
+
focus?: string | undefined;
|
|
169
|
+
} | undefined;
|
|
170
|
+
favicon?: {
|
|
171
|
+
src: string;
|
|
172
|
+
alt: string;
|
|
173
|
+
fit: "cover" | "contain";
|
|
174
|
+
size: "fill" | "natural";
|
|
175
|
+
focus?: string | undefined;
|
|
176
|
+
} | undefined;
|
|
177
|
+
palette?: {
|
|
178
|
+
dark: string;
|
|
179
|
+
primary: string;
|
|
180
|
+
accent: string;
|
|
181
|
+
} | undefined;
|
|
182
|
+
footer?: string | undefined;
|
|
183
|
+
}, {
|
|
184
|
+
key: string;
|
|
185
|
+
name: string;
|
|
186
|
+
tagline?: string | undefined;
|
|
187
|
+
logo?: unknown;
|
|
188
|
+
logoOnDark?: unknown;
|
|
189
|
+
favicon?: unknown;
|
|
190
|
+
palette?: {
|
|
191
|
+
dark: string;
|
|
192
|
+
primary: string;
|
|
193
|
+
accent: string;
|
|
194
|
+
} | undefined;
|
|
195
|
+
footer?: string | undefined;
|
|
196
|
+
}>;
|
|
197
|
+
type BrandProfileInput = z.input<typeof BrandProfileSchema>;
|
|
198
|
+
type BrandProfile = z.output<typeof BrandProfileSchema>;
|
|
199
|
+
/** Per-deck brand choice and overrides (deck.brand). */
|
|
200
|
+
declare const DeckBrandSchema: z.ZodObject<{
|
|
201
|
+
profile: z.ZodOptional<z.ZodString>;
|
|
202
|
+
name: z.ZodOptional<z.ZodString>;
|
|
203
|
+
tagline: z.ZodOptional<z.ZodString>;
|
|
204
|
+
logo: z.ZodOptional<z.ZodEffects<z.ZodObject<{
|
|
205
|
+
src: z.ZodString;
|
|
206
|
+
alt: z.ZodDefault<z.ZodString>;
|
|
207
|
+
fit: z.ZodDefault<z.ZodEnum<["cover", "contain"]>>;
|
|
208
|
+
size: z.ZodDefault<z.ZodEnum<["fill", "natural"]>>;
|
|
209
|
+
focus: z.ZodOptional<z.ZodString>;
|
|
210
|
+
}, "strip", z.ZodTypeAny, {
|
|
211
|
+
src: string;
|
|
212
|
+
alt: string;
|
|
213
|
+
fit: "cover" | "contain";
|
|
214
|
+
size: "fill" | "natural";
|
|
215
|
+
focus?: string | undefined;
|
|
216
|
+
}, {
|
|
217
|
+
src: string;
|
|
218
|
+
alt?: string | undefined;
|
|
219
|
+
fit?: "cover" | "contain" | undefined;
|
|
220
|
+
size?: "fill" | "natural" | undefined;
|
|
221
|
+
focus?: string | undefined;
|
|
222
|
+
}>, {
|
|
223
|
+
src: string;
|
|
224
|
+
alt: string;
|
|
225
|
+
fit: "cover" | "contain";
|
|
226
|
+
size: "fill" | "natural";
|
|
227
|
+
focus?: string | undefined;
|
|
228
|
+
}, unknown>>;
|
|
229
|
+
logoOnDark: z.ZodOptional<z.ZodEffects<z.ZodObject<{
|
|
230
|
+
src: z.ZodString;
|
|
231
|
+
alt: z.ZodDefault<z.ZodString>;
|
|
232
|
+
fit: z.ZodDefault<z.ZodEnum<["cover", "contain"]>>;
|
|
233
|
+
size: z.ZodDefault<z.ZodEnum<["fill", "natural"]>>;
|
|
234
|
+
focus: z.ZodOptional<z.ZodString>;
|
|
235
|
+
}, "strip", z.ZodTypeAny, {
|
|
236
|
+
src: string;
|
|
237
|
+
alt: string;
|
|
238
|
+
fit: "cover" | "contain";
|
|
239
|
+
size: "fill" | "natural";
|
|
240
|
+
focus?: string | undefined;
|
|
241
|
+
}, {
|
|
242
|
+
src: string;
|
|
243
|
+
alt?: string | undefined;
|
|
244
|
+
fit?: "cover" | "contain" | undefined;
|
|
245
|
+
size?: "fill" | "natural" | undefined;
|
|
246
|
+
focus?: string | undefined;
|
|
247
|
+
}>, {
|
|
248
|
+
src: string;
|
|
249
|
+
alt: string;
|
|
250
|
+
fit: "cover" | "contain";
|
|
251
|
+
size: "fill" | "natural";
|
|
252
|
+
focus?: string | undefined;
|
|
253
|
+
}, unknown>>;
|
|
254
|
+
favicon: z.ZodOptional<z.ZodEffects<z.ZodObject<{
|
|
255
|
+
src: z.ZodString;
|
|
256
|
+
alt: z.ZodDefault<z.ZodString>;
|
|
257
|
+
fit: z.ZodDefault<z.ZodEnum<["cover", "contain"]>>;
|
|
258
|
+
size: z.ZodDefault<z.ZodEnum<["fill", "natural"]>>;
|
|
259
|
+
focus: z.ZodOptional<z.ZodString>;
|
|
260
|
+
}, "strip", z.ZodTypeAny, {
|
|
261
|
+
src: string;
|
|
262
|
+
alt: string;
|
|
263
|
+
fit: "cover" | "contain";
|
|
264
|
+
size: "fill" | "natural";
|
|
265
|
+
focus?: string | undefined;
|
|
266
|
+
}, {
|
|
267
|
+
src: string;
|
|
268
|
+
alt?: string | undefined;
|
|
269
|
+
fit?: "cover" | "contain" | undefined;
|
|
270
|
+
size?: "fill" | "natural" | undefined;
|
|
271
|
+
focus?: string | undefined;
|
|
272
|
+
}>, {
|
|
273
|
+
src: string;
|
|
274
|
+
alt: string;
|
|
275
|
+
fit: "cover" | "contain";
|
|
276
|
+
size: "fill" | "natural";
|
|
277
|
+
focus?: string | undefined;
|
|
278
|
+
}, unknown>>;
|
|
279
|
+
footer: z.ZodOptional<z.ZodString>;
|
|
280
|
+
}, "strict", z.ZodTypeAny, {
|
|
281
|
+
name?: string | undefined;
|
|
282
|
+
tagline?: string | undefined;
|
|
283
|
+
logo?: {
|
|
284
|
+
src: string;
|
|
285
|
+
alt: string;
|
|
286
|
+
fit: "cover" | "contain";
|
|
287
|
+
size: "fill" | "natural";
|
|
288
|
+
focus?: string | undefined;
|
|
289
|
+
} | undefined;
|
|
290
|
+
logoOnDark?: {
|
|
291
|
+
src: string;
|
|
292
|
+
alt: string;
|
|
293
|
+
fit: "cover" | "contain";
|
|
294
|
+
size: "fill" | "natural";
|
|
295
|
+
focus?: string | undefined;
|
|
296
|
+
} | undefined;
|
|
297
|
+
favicon?: {
|
|
298
|
+
src: string;
|
|
299
|
+
alt: string;
|
|
300
|
+
fit: "cover" | "contain";
|
|
301
|
+
size: "fill" | "natural";
|
|
302
|
+
focus?: string | undefined;
|
|
303
|
+
} | undefined;
|
|
304
|
+
footer?: string | undefined;
|
|
305
|
+
profile?: string | undefined;
|
|
306
|
+
}, {
|
|
307
|
+
name?: string | undefined;
|
|
308
|
+
tagline?: string | undefined;
|
|
309
|
+
logo?: unknown;
|
|
310
|
+
logoOnDark?: unknown;
|
|
311
|
+
favicon?: unknown;
|
|
312
|
+
footer?: string | undefined;
|
|
313
|
+
profile?: string | undefined;
|
|
314
|
+
}>;
|
|
315
|
+
type DeckBrand = z.output<typeof DeckBrandSchema>;
|
|
316
|
+
declare const CLASSIC_HOMES_PALETTE: BrandPalette;
|
|
317
|
+
declare const CLASSIC_HOMES_BRAND: BrandProfile;
|
|
318
|
+
interface ResolvedBrand {
|
|
319
|
+
key: string;
|
|
320
|
+
name: string;
|
|
321
|
+
tagline?: string;
|
|
322
|
+
footer?: string;
|
|
323
|
+
logo?: ImageValue;
|
|
324
|
+
logoOnDark?: ImageValue;
|
|
325
|
+
favicon?: ImageValue;
|
|
326
|
+
palette: BrandPalette;
|
|
327
|
+
/** True when the palette is the stock Classic Homes one. */
|
|
328
|
+
stock: boolean;
|
|
329
|
+
}
|
|
330
|
+
/** Merges defaults ← profile ← deck overrides. Unknown profiles fall back to the default (validation reports them). */
|
|
331
|
+
declare function resolveBrand(deckBrand: DeckBrand | undefined, brands?: BrandProfile[]): ResolvedBrand;
|
|
332
|
+
interface PaletteIssue {
|
|
333
|
+
field: keyof BrandPalette;
|
|
334
|
+
message: string;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Every palette colour is used both as text on the light paper ground and as
|
|
338
|
+
* a solid ground under white text, so each must reach WCAG AA (4.5:1) both ways.
|
|
339
|
+
*/
|
|
340
|
+
declare function checkPalette(palette: BrandPalette): PaletteIssue[];
|
|
341
|
+
/** Validates an admin-supplied profile: schema plus contrast. */
|
|
342
|
+
declare function validateBrandProfile(input: unknown): {
|
|
343
|
+
ok: true;
|
|
344
|
+
profile: BrandProfile;
|
|
345
|
+
} | {
|
|
346
|
+
ok: false;
|
|
347
|
+
issues: {
|
|
348
|
+
path: (string | number)[];
|
|
349
|
+
message: string;
|
|
350
|
+
}[];
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/** The deck-level fields a layout may read while rendering. */
|
|
354
|
+
interface DeckContext {
|
|
355
|
+
title: string;
|
|
356
|
+
journey?: {
|
|
357
|
+
steps: string[];
|
|
358
|
+
label: string;
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
/** A chart to pre-render before slides are rendered (see charts.ts). */
|
|
362
|
+
interface ChartRequest {
|
|
363
|
+
key: string;
|
|
364
|
+
spec: unknown;
|
|
365
|
+
width: number;
|
|
366
|
+
height: number;
|
|
367
|
+
}
|
|
368
|
+
interface RenderContext {
|
|
369
|
+
deck: DeckContext;
|
|
370
|
+
/** Resolved image sources (original src → data URI or URL). */
|
|
371
|
+
image(src: string): string;
|
|
372
|
+
/** Pre-rendered QR code SVG for a URL (declare URLs in `prepare`). */
|
|
373
|
+
qr(url: string): string;
|
|
374
|
+
/** Pre-rendered chart SVG (declare charts in `prepare`). */
|
|
375
|
+
chart(key: string): string;
|
|
376
|
+
/** The deck's logo lockup for this brand ('' when settings.logo is 'none'). */
|
|
377
|
+
logo(): string;
|
|
378
|
+
/** Resolved brand name. */
|
|
379
|
+
brandName: string;
|
|
380
|
+
}
|
|
381
|
+
/** Async work a layout needs done before render: QR codes and charts. */
|
|
382
|
+
interface Prepared {
|
|
383
|
+
qr?: string[];
|
|
384
|
+
charts?: ChartRequest[];
|
|
385
|
+
/** Extra image URLs to resolve (inline) that are not `src` fields, e.g. video posters. */
|
|
386
|
+
images?: string[];
|
|
387
|
+
}
|
|
388
|
+
/** One rendered <section>. Layouts return several when one entry expands into a sequence. */
|
|
389
|
+
interface RenderedSlide {
|
|
390
|
+
html: string;
|
|
391
|
+
/** Extra classes on the section (layout class is added automatically). */
|
|
392
|
+
classes?: string[];
|
|
393
|
+
/** Overrides the slide's own notes (e.g. per-stage notes in a walkthrough). */
|
|
394
|
+
notes?: string;
|
|
395
|
+
time?: string;
|
|
396
|
+
}
|
|
397
|
+
interface LayoutIssue {
|
|
398
|
+
level: 'error' | 'warning';
|
|
399
|
+
path: (string | number)[];
|
|
400
|
+
message: string;
|
|
401
|
+
}
|
|
402
|
+
interface LayoutDef<Shape extends z.ZodRawShape = z.ZodRawShape> {
|
|
403
|
+
/** Value of `layout` in the deck file. */
|
|
404
|
+
name: string;
|
|
405
|
+
/** One line: what the slide looks like. */
|
|
406
|
+
description: string;
|
|
407
|
+
/** When an author or agent should pick this layout. */
|
|
408
|
+
whenToUse: string;
|
|
409
|
+
/** Layout-specific fields (base slide fields are added by the deck schema). */
|
|
410
|
+
shape: Shape;
|
|
411
|
+
/** Defaults applied when the slide leaves them unset. */
|
|
412
|
+
defaults?: {
|
|
413
|
+
background?: string;
|
|
414
|
+
track?: 'value' | 'build' | 'neutral';
|
|
415
|
+
};
|
|
416
|
+
/** A complete, valid example slide. */
|
|
417
|
+
example: Record<string, unknown>;
|
|
418
|
+
/** Declares QR codes / charts to pre-render for this slide. */
|
|
419
|
+
prepare?(slide: z.infer<z.ZodObject<Shape>>): Prepared;
|
|
420
|
+
/** Soft checks beyond the schema: length and density limits that keep slides clean. */
|
|
421
|
+
lint?(slide: z.infer<z.ZodObject<Shape>>): LayoutIssue[];
|
|
422
|
+
render(slide: z.infer<z.ZodObject<Shape>>, ctx: RenderContext): RenderedSlide | RenderedSlide[];
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Every layout, in the order they are offered to authors. */
|
|
426
|
+
declare const LAYOUTS: readonly LayoutDef<any>[];
|
|
427
|
+
type LayoutName = 'title' | 'section' | 'statement' | 'bullets' | 'split' | 'cards' | 'stats' | 'comparison' | 'journey' | 'photos' | 'image' | 'walkthrough' | 'quote' | 'qr' | 'contacts' | 'chart' | 'table' | 'flow' | 'timeline' | 'cycle' | 'hierarchy' | 'matrix' | 'tiers' | 'video' | 'embed' | 'compare';
|
|
428
|
+
declare function getLayout(name: string): LayoutDef | undefined;
|
|
429
|
+
|
|
430
|
+
type LayoutCategory = 'Openers & dividers' | 'Text' | 'Data' | 'Diagrams' | 'Media' | 'People & places';
|
|
431
|
+
/** Category display order for layout pickers. */
|
|
432
|
+
declare const LAYOUT_CATEGORY_ORDER: LayoutCategory[];
|
|
433
|
+
/** Category of each layout. */
|
|
434
|
+
declare const LAYOUT_CATEGORIES: Record<LayoutName, LayoutCategory>;
|
|
435
|
+
|
|
436
|
+
/** Fields every slide has after parsing; layout-specific fields ride along. */
|
|
437
|
+
interface SlideData {
|
|
438
|
+
layout: LayoutName;
|
|
439
|
+
id?: string;
|
|
440
|
+
track?: 'value' | 'build' | 'neutral';
|
|
441
|
+
background?: 'paper' | 'navy' | 'slate' | 'red' | 'teal' | 'plum' | 'grey' | 'stone';
|
|
442
|
+
notes?: string;
|
|
443
|
+
time?: string;
|
|
444
|
+
step?: number;
|
|
445
|
+
stepDone?: boolean;
|
|
446
|
+
showJourney?: boolean;
|
|
447
|
+
hidden?: boolean;
|
|
448
|
+
backgroundImage?: ImageValue;
|
|
449
|
+
overlay?: 'dark' | 'light' | 'brand';
|
|
450
|
+
[field: string]: unknown;
|
|
451
|
+
}
|
|
452
|
+
interface Deck {
|
|
453
|
+
title: string;
|
|
454
|
+
description?: string;
|
|
455
|
+
author?: string;
|
|
456
|
+
date?: string;
|
|
457
|
+
lang: string;
|
|
458
|
+
journey?: {
|
|
459
|
+
steps: string[];
|
|
460
|
+
label: string;
|
|
461
|
+
};
|
|
462
|
+
brand?: DeckBrand;
|
|
463
|
+
settings: DeckSettings;
|
|
464
|
+
slides: SlideData[];
|
|
465
|
+
}
|
|
466
|
+
interface DeckSettings {
|
|
467
|
+
slideNumbers: boolean;
|
|
468
|
+
logo: 'title' | 'all' | 'none';
|
|
469
|
+
confidential?: string;
|
|
470
|
+
autoAdvance?: number;
|
|
471
|
+
loop: boolean;
|
|
472
|
+
}
|
|
473
|
+
/** A deck as authored (before defaults are applied). */
|
|
474
|
+
type DeckInput = Omit<Partial<Deck>, 'slides' | 'journey' | 'settings'> & {
|
|
475
|
+
settings?: Partial<DeckSettings>;
|
|
476
|
+
title: string;
|
|
477
|
+
journey?: {
|
|
478
|
+
steps: string[];
|
|
479
|
+
label?: string;
|
|
480
|
+
};
|
|
481
|
+
slides: ({
|
|
482
|
+
layout: LayoutName;
|
|
483
|
+
} & Record<string, unknown>)[];
|
|
484
|
+
};
|
|
485
|
+
type SlideInput = DeckInput['slides'][number];
|
|
486
|
+
declare const SlideSchema: z.ZodType<SlideData, z.ZodTypeDef, unknown>;
|
|
487
|
+
declare const DeckSettingsSchema: z.ZodObject<{
|
|
488
|
+
slideNumbers: z.ZodDefault<z.ZodBoolean>;
|
|
489
|
+
logo: z.ZodDefault<z.ZodEnum<["title", "all", "none"]>>;
|
|
490
|
+
confidential: z.ZodOptional<z.ZodString>;
|
|
491
|
+
autoAdvance: z.ZodOptional<z.ZodNumber>;
|
|
492
|
+
loop: z.ZodDefault<z.ZodBoolean>;
|
|
493
|
+
}, "strict", z.ZodTypeAny, {
|
|
494
|
+
logo: "title" | "all" | "none";
|
|
495
|
+
slideNumbers: boolean;
|
|
496
|
+
loop: boolean;
|
|
497
|
+
confidential?: string | undefined;
|
|
498
|
+
autoAdvance?: number | undefined;
|
|
499
|
+
}, {
|
|
500
|
+
logo?: "title" | "all" | "none" | undefined;
|
|
501
|
+
slideNumbers?: boolean | undefined;
|
|
502
|
+
confidential?: string | undefined;
|
|
503
|
+
autoAdvance?: number | undefined;
|
|
504
|
+
loop?: boolean | undefined;
|
|
505
|
+
}>;
|
|
506
|
+
declare const DeckSchema: z.ZodType<Deck, z.ZodTypeDef, unknown>;
|
|
507
|
+
|
|
508
|
+
interface ValidationResult {
|
|
509
|
+
ok: boolean;
|
|
510
|
+
deck?: Deck;
|
|
511
|
+
/** Errors block rendering; warnings are advice that keeps slides clean. */
|
|
512
|
+
issues: LayoutIssue[];
|
|
513
|
+
}
|
|
514
|
+
interface ValidateOptions {
|
|
515
|
+
/** Brand profiles `deck.brand.profile` may reference (classic-homes is built in). */
|
|
516
|
+
brands?: BrandProfile[];
|
|
517
|
+
}
|
|
518
|
+
declare function validateDeck(input: unknown, options?: ValidateOptions): ValidationResult;
|
|
519
|
+
/** Human path: slides.3.items.0 → "slide 4 › items › 1" (positions are 1-based, like the outline). */
|
|
520
|
+
declare function formatPath(path: (string | number)[]): string;
|
|
521
|
+
declare function formatIssues(issues: LayoutIssue[]): string;
|
|
522
|
+
declare class DeckError extends Error {
|
|
523
|
+
issues: LayoutIssue[];
|
|
524
|
+
constructor(issues: LayoutIssue[]);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Size to lay a preview out at before scaling it down. Slides are responsive
|
|
529
|
+
* and switch to a stacked layout below ~840px wide, so small previews should
|
|
530
|
+
* render at this size and use a CSS transform.
|
|
531
|
+
*/
|
|
532
|
+
declare const PREVIEW_SIZE: {
|
|
533
|
+
readonly width: 1280;
|
|
534
|
+
readonly height: 720;
|
|
535
|
+
};
|
|
536
|
+
type ImageResolver = (src: string) => Promise<string> | string;
|
|
537
|
+
interface RenderOptions {
|
|
538
|
+
/**
|
|
539
|
+
* Turns an image `src` from the deck into something the browser can load,
|
|
540
|
+
* normally a data: URI so the file stays self-contained. The default passes
|
|
541
|
+
* data: and https: URLs through and rejects everything else.
|
|
542
|
+
*/
|
|
543
|
+
resolveImage?: ImageResolver;
|
|
544
|
+
/**
|
|
545
|
+
* Maximum escaped UTF-8 bytes of data-URI images emitted into HTML, counting
|
|
546
|
+
* every occurrence (including repeated logos, backgrounds and favicon).
|
|
547
|
+
* Over-budget resolved images retain their original https URL. Authored
|
|
548
|
+
* data URIs/local images with no safe remote fallback raise DeckError.
|
|
549
|
+
* Fixed embedded fonts are excluded. Omit for unrestricted local exports.
|
|
550
|
+
*/
|
|
551
|
+
maxInlineImageBytes?: number;
|
|
552
|
+
/** Embed the deck source (JSON, without image data) so the HTML can be re-opened for editing. Default true. */
|
|
553
|
+
embedSource?: boolean;
|
|
554
|
+
/** 0-based rendered slide to open on (ignored when the URL has #slide-N). Handy for editor previews. */
|
|
555
|
+
initialSlide?: number;
|
|
556
|
+
/** Brand profiles available to `deck.brand.profile` (the built-in classic-homes profile is always present). */
|
|
557
|
+
brands?: BrandProfile[];
|
|
558
|
+
/** Render slides marked `hidden` too (dimmed, badged). For editor previews. */
|
|
559
|
+
includeHidden?: boolean;
|
|
560
|
+
/** Include speaker notes, the notes panel and the presenter window. Default true; turn off for shared links. */
|
|
561
|
+
speakerNotes?: boolean;
|
|
562
|
+
/** Permit kiosk auto-advance in an isolated presentation host (editor previews stay paused). */
|
|
563
|
+
allowEmbeddedKiosk?: boolean;
|
|
564
|
+
/**
|
|
565
|
+
* Click-to-edit for editor previews. Embeds each slide's text and image
|
|
566
|
+
* fields so that, inside an iframe, clicking a title, bullet or picture
|
|
567
|
+
* posts `{ type: 'classic-slides:select', index, path }` to the parent
|
|
568
|
+
* (`index` is the deck slide, `path` the field, or null for the slide
|
|
569
|
+
* itself), and the parent can outline a field with
|
|
570
|
+
* `{ type: 'classic-slides:highlight', index, path }`. Links inside slides
|
|
571
|
+
* stop navigating. Off by default; never use it for shared or exported decks.
|
|
572
|
+
*/
|
|
573
|
+
editorMarkers?: boolean;
|
|
574
|
+
}
|
|
575
|
+
/** A field the editor runtime can match a clicked element to. */
|
|
576
|
+
interface FieldMarker {
|
|
577
|
+
/** Path inside the slide, e.g. ["title"] or ["items", 2, "text"] */
|
|
578
|
+
path: (string | number)[];
|
|
579
|
+
/** Visible text of a text field, whitespace collapsed */
|
|
580
|
+
text?: string;
|
|
581
|
+
/** Resolved src of an image field */
|
|
582
|
+
img?: string;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* The text and image fields of one slide, for click-to-edit matching.
|
|
586
|
+
* `resolveImage` maps an authored src to the src rendered in the page.
|
|
587
|
+
*/
|
|
588
|
+
declare function fieldMarkers(slide: Record<string, unknown>, resolveImage?: (src: string) => string): FieldMarker[];
|
|
589
|
+
interface RenderResult {
|
|
590
|
+
html: string;
|
|
591
|
+
deck: Deck;
|
|
592
|
+
slideCount: number;
|
|
593
|
+
/** For each deck slide, the 0-based indices of the rendered slides it produced (a walkthrough yields several). */
|
|
594
|
+
slideMap: number[][];
|
|
595
|
+
warnings: ReturnType<typeof validateDeck>['issues'];
|
|
596
|
+
brand: ResolvedBrand;
|
|
597
|
+
}
|
|
598
|
+
/** Collects every image src in the deck (any object with a string `src`). */
|
|
599
|
+
declare function collectImageSources(value: unknown, out?: Set<string>): Set<string>;
|
|
600
|
+
declare function renderDeck(input: unknown, options?: RenderOptions): Promise<RenderResult>;
|
|
601
|
+
/** Pulls the embedded deck source back out of a rendered HTML file. */
|
|
602
|
+
declare function extractDeckSource(html: string): unknown | undefined;
|
|
603
|
+
|
|
604
|
+
export { checkPalette as A, type BrandPalette as B, CLASSIC_HOMES_BRAND as C, type Deck as D, collectImageSources as E, type FieldMarker as F, extractDeckSource as G, fieldMarkers as H, type ImageInput as I, formatIssues as J, formatPath as K, type LayoutCategory as L, getLayout as M, renderDeck as N, resolveBrand as O, PREVIEW_SIZE as P, validateBrandProfile as Q, type RenderOptions as R, type SlideData as S, validateDeck as T, type ValidateOptions as V, BrandPaletteSchema as a, type BrandProfile as b, type BrandProfileInput as c, BrandProfileSchema as d, CLASSIC_HOMES_PALETTE as e, type DeckBrand as f, DeckBrandSchema as g, DeckError as h, type DeckInput as i, DeckSchema as j, type DeckSettings as k, DeckSettingsSchema as l, type ImageResolver as m, type ImageValue as n, type ItemValue as o, LAYOUTS as p, LAYOUT_CATEGORIES as q, LAYOUT_CATEGORY_ORDER as r, type LayoutDef as s, type LayoutIssue as t, type LayoutName as u, type RenderResult as v, type ResolvedBrand as w, type SlideInput as x, SlideSchema as y, type ValidationResult as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classic-homes/slides",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Branded Classic Homes presentations from structured deck files: schema, layouts, renderer, CLI and MCP server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -51,7 +51,9 @@
|
|
|
51
51
|
"clean": "node ../../scripts/rm.mjs dist src/generated"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
+
"@classic-homes/charts-core": "^0.1.36",
|
|
54
55
|
"@classic-homes/theme-tokens": "^0.4.0",
|
|
56
|
+
"echarts": "^5.5.0",
|
|
55
57
|
"qrcode": "^1.5.4",
|
|
56
58
|
"yaml": "^2.6.0",
|
|
57
59
|
"zod": "^3.25.0",
|
package/dist/chunk-33EPZMT6.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DeckSchema,
|
|
3
|
-
LAYOUTS,
|
|
4
|
-
baseSlide,
|
|
5
|
-
getLayout
|
|
6
|
-
} from "./chunk-7FROOJCY.js";
|
|
7
|
-
|
|
8
|
-
// src/catalog.ts
|
|
9
|
-
import { z } from "zod";
|
|
10
|
-
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
11
|
-
function listLayouts() {
|
|
12
|
-
return LAYOUTS.map((l) => ({ name: l.name, description: l.description, whenToUse: l.whenToUse }));
|
|
13
|
-
}
|
|
14
|
-
function describeLayout(name) {
|
|
15
|
-
const layout = getLayout(name);
|
|
16
|
-
if (!layout) return void 0;
|
|
17
|
-
const schema = z.object({ layout: z.literal(layout.name), ...layout.shape, ...baseSlide });
|
|
18
|
-
return {
|
|
19
|
-
name: layout.name,
|
|
20
|
-
description: layout.description,
|
|
21
|
-
whenToUse: layout.whenToUse,
|
|
22
|
-
defaults: layout.defaults ?? {},
|
|
23
|
-
schema: zodToJsonSchema(schema, { $refStrategy: "none" }),
|
|
24
|
-
example: layout.example
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
function deckJsonSchema() {
|
|
28
|
-
return zodToJsonSchema(DeckSchema, { name: "ClassicDeck", $refStrategy: "none" });
|
|
29
|
-
}
|
|
30
|
-
var AUTHORING_GUIDE = `# Writing a Classic Homes deck
|
|
31
|
-
|
|
32
|
-
A deck is a YAML (or JSON) file: deck-level fields plus a list of slides. Each slide
|
|
33
|
-
picks a **layout** and fills its fields. Layouts own all styling \u2014 there is no way to
|
|
34
|
-
set colours, fonts or sizes directly, which is what keeps every deck on-brand.
|
|
35
|
-
|
|
36
|
-
## Principles
|
|
37
|
-
- **One idea per slide.** The headline states the point. Detail goes in \`notes\`.
|
|
38
|
-
- **Short copy.** Titles under ~70 characters, bullets a few words, at most 6 bullets.
|
|
39
|
-
\`validate\` warns when a slide gets crowded \u2014 split it rather than shrinking text.
|
|
40
|
-
- **Speaker notes on every content slide.** Presenters press N to see them.
|
|
41
|
-
- **Real photos over decoration.** Every image needs \`alt\` text.
|
|
42
|
-
- **Tracks** colour the accent: \`value\` (red, default) for the homeowner/value story,
|
|
43
|
-
\`build\` (teal) for construction/process, \`neutral\` (navy) for framing slides.
|
|
44
|
-
- **Backgrounds**: \`paper\` (default) for content; solid \`navy\`/\`red\`/\`teal\`/\`plum\`/\`grey\`/\`stone\`
|
|
45
|
-
for section dividers and moments of emphasis. Don't put dense content on solid grounds.
|
|
46
|
-
|
|
47
|
-
## Inline text
|
|
48
|
-
\`**bold**\`, \`*highlight*\` (accent colour), \`\\\`code\\\`\`, \`[label](https://\u2026)\`. No HTML.
|
|
49
|
-
|
|
50
|
-
## Journey decks
|
|
51
|
-
Set \`journey.steps\` at deck level to get a numbered agenda. Then:
|
|
52
|
-
- a \`journey\` slide shows the full map,
|
|
53
|
-
- \`step: 3\` on any slide draws the vertical STEP rail,
|
|
54
|
-
- \`showJourney: true\` adds the compact "you are here" strip (great on \`section\` slides).
|
|
55
|
-
|
|
56
|
-
## Typical shape
|
|
57
|
-
1. \`title\`
|
|
58
|
-
2. \`statement\` or \`journey\` (why we're here / the agenda)
|
|
59
|
-
3. per part: \`section\` \u2192 2\u20135 content slides (\`bullets\`, \`split\`, \`cards\`, \`stats\`, \`photos\`, \`walkthrough\`)
|
|
60
|
-
4. \`qr\` (where to go next) \u2192 \`contacts\` \u2192 closing \`statement\`
|
|
61
|
-
`;
|
|
62
|
-
|
|
63
|
-
export {
|
|
64
|
-
listLayouts,
|
|
65
|
-
describeLayout,
|
|
66
|
-
deckJsonSchema,
|
|
67
|
-
AUTHORING_GUIDE
|
|
68
|
-
};
|
|
69
|
-
//# sourceMappingURL=chunk-33EPZMT6.js.map
|