@tycoworks/tycoslide 0.10.1 → 0.11.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 +2 -0
- package/SKILL.md +28 -54
- package/dist/cli.js +4 -4
- package/dist/engine/fillers/filler.d.ts +31 -5
- package/dist/engine/fillers/filler.js +29 -21
- package/dist/engine/fillers/image.d.ts +1 -1
- package/dist/engine/fillers/image.js +2 -2
- package/dist/engine/fillers/table.d.ts +33 -16
- package/dist/engine/fillers/table.js +62 -27
- package/dist/engine/generate.d.ts +5 -4
- package/dist/engine/generate.js +51 -17
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/types.d.ts +41 -13
- package/dist/index.d.ts +3 -4
- package/dist/index.js +28 -15
- package/dist/manifest.d.ts +1 -6
- package/dist/manifest.js +1 -17
- package/dist/markdown/blocks/mermaid.d.ts +1 -1
- package/dist/markdown/blocks/mermaid.js +3 -3
- package/dist/markdown/blocks/table.js +1 -1
- package/dist/markdown/blocks/text.js +5 -6
- package/dist/markdown/deckCompiler.d.ts +2 -2
- package/dist/markdown/deckCompiler.js +7 -32
- package/dist/markdown/index.d.ts +1 -1
- package/dist/markdown/schema/deckSchema.d.ts +2 -2
- package/dist/markdown/schema/deckSchema.js +2 -2
- package/dist/markdown/schema/themeConfigSchema.d.ts +12 -21
- package/dist/markdown/schema/themeConfigSchema.js +22 -14
- package/dist/markdown/slideParser.d.ts +0 -1
- package/dist/markdown/slideParser.js +7 -4
- package/dist/markdown/types.d.ts +44 -46
- package/dist/markdown/types.js +2 -4
- package/package.json +1 -1
- package/syntax.md +28 -25
|
@@ -21,9 +21,12 @@ import { strict } from "./strict.js";
|
|
|
21
21
|
* `z.record`, open by design); strictness lands on their leaf entries.
|
|
22
22
|
*/
|
|
23
23
|
// Reuse the const-object enums as runtime values — no third copy of the literals.
|
|
24
|
-
const acceptTypeSchema = z.enum(Object.values(AcceptType));
|
|
25
24
|
const assetTypeSchema = z.enum(Object.values(AssetType));
|
|
26
25
|
const variantSchema = z.enum(Object.values(Variant));
|
|
26
|
+
// A table specimen's repeatable row range: `[start, end]`, 0-based inclusive,
|
|
27
|
+
// non-negative integers. The range is validated against the specimen's actual row
|
|
28
|
+
// count at fill time, where the row count is known.
|
|
29
|
+
const bodyRowsSchema = z.tuple([z.number().int().nonnegative(), z.number().int().nonnegative()]);
|
|
27
30
|
// Re-declared here (not imported from the engine) so the schema layer never
|
|
28
31
|
// depends on the engine — mirrors engine `Frame`, guarded by `_drift`.
|
|
29
32
|
const FrameSchema = strict({
|
|
@@ -32,16 +35,10 @@ const FrameSchema = strict({
|
|
|
32
35
|
cx: z.number(),
|
|
33
36
|
cy: z.number(),
|
|
34
37
|
});
|
|
35
|
-
const LimitSchema = strict({
|
|
36
|
-
maxChars: z.number().optional(),
|
|
37
|
-
maxLines: z.number().optional(),
|
|
38
|
-
maxItems: z.number().optional(),
|
|
39
|
-
});
|
|
40
38
|
const AssetEntrySchema = strict({
|
|
41
39
|
path: z.string(),
|
|
42
40
|
type: assetTypeSchema,
|
|
43
41
|
description: z.string(),
|
|
44
|
-
whenToUse: z.string().optional(),
|
|
45
42
|
});
|
|
46
43
|
// AssetCatalog: `{ category: { name: AssetEntry } }`. The two record levels are
|
|
47
44
|
// OPEN (names are user-defined); only the leaf entry is strict.
|
|
@@ -68,7 +65,6 @@ const ThemeFontSchema = strict({
|
|
|
68
65
|
});
|
|
69
66
|
const TemplateParamSchema = strict({
|
|
70
67
|
shapeName: z.string(),
|
|
71
|
-
limit: LimitSchema.optional(),
|
|
72
68
|
required: z.boolean().optional(),
|
|
73
69
|
type: z.literal(ParameterType.Template),
|
|
74
70
|
template: z.string(),
|
|
@@ -80,25 +76,38 @@ const ImageParamSchema = strict({
|
|
|
80
76
|
type: z.literal(ParameterType.Image),
|
|
81
77
|
});
|
|
82
78
|
const ParameterSchema = z.discriminatedUnion("type", [TemplateParamSchema, ImageParamSchema]);
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
// One arm per accept type, discriminated by `type`, mirroring `CompilerBlock`:
|
|
80
|
+
// `startAt` lives only on the text arm, and `bodyRows` only on the table arm (a
|
|
81
|
+
// table block MUST declare its repeatable-row range; text/image arms have no
|
|
82
|
+
// `bodyRows` field, so a stray one is an unknown key the `strict` arm rejects).
|
|
83
|
+
const TextBlockSchema = strict({
|
|
84
|
+
type: z.literal(AcceptType.Text),
|
|
85
85
|
sourceSlide: z.number(),
|
|
86
86
|
shapeName: z.string(),
|
|
87
87
|
startAt: z.number().optional(),
|
|
88
88
|
});
|
|
89
|
+
const TableBlockSchema = strict({
|
|
90
|
+
type: z.literal(AcceptType.Table),
|
|
91
|
+
sourceSlide: z.number(),
|
|
92
|
+
shapeName: z.string(),
|
|
93
|
+
bodyRows: bodyRowsSchema,
|
|
94
|
+
});
|
|
95
|
+
const ImageBlockSchema = strict({
|
|
96
|
+
type: z.literal(AcceptType.Image),
|
|
97
|
+
sourceSlide: z.number(),
|
|
98
|
+
shapeName: z.string(),
|
|
99
|
+
});
|
|
100
|
+
const BlockSchema = z.discriminatedUnion("type", [TextBlockSchema, TableBlockSchema, ImageBlockSchema]);
|
|
89
101
|
const SlotSchema = strict({
|
|
90
102
|
key: z.string(),
|
|
91
103
|
accepts: z.array(BlockSchema),
|
|
92
104
|
frame: FrameSchema.optional(),
|
|
93
|
-
limit: LimitSchema.optional(),
|
|
94
105
|
required: z.boolean().optional(),
|
|
95
106
|
});
|
|
96
107
|
const LayoutSchema = strict({
|
|
97
108
|
name: z.string(),
|
|
98
109
|
slideNumber: z.number(),
|
|
99
110
|
description: z.string().optional(),
|
|
100
|
-
whenToUse: z.string().optional(),
|
|
101
|
-
whenNotToUse: z.string().optional(),
|
|
102
111
|
variant: variantSchema.optional(),
|
|
103
112
|
parameters: z.array(ParameterSchema),
|
|
104
113
|
slots: z.array(SlotSchema),
|
|
@@ -107,7 +116,6 @@ export const ThemeConfigSchema = strict({
|
|
|
107
116
|
layouts: z.array(LayoutSchema),
|
|
108
117
|
assets: AssetCatalogSchema,
|
|
109
118
|
template: z.string(),
|
|
110
|
-
outputDir: z.string().optional(),
|
|
111
119
|
mermaid: MermaidConfigSchema.optional(),
|
|
112
120
|
fonts: z.array(ThemeFontSchema).optional(),
|
|
113
121
|
codeTheme: z.union([z.string(), strict({ light: z.string().min(1), dark: z.string().min(1) })]).optional(),
|
|
@@ -123,8 +123,11 @@ function splitIntoSlides(text) {
|
|
|
123
123
|
// ============================================
|
|
124
124
|
function buildSlide(index, fmString, rawContent) {
|
|
125
125
|
const frontmatter = parseFrontmatter(fmString, index);
|
|
126
|
-
const {
|
|
127
|
-
|
|
126
|
+
const { leading, slots } = extractSlots(rawContent);
|
|
127
|
+
if (leading.trim()) {
|
|
128
|
+
throw new Error(`Slide ${index + 1}: text found outside a ::slot:: marker`);
|
|
129
|
+
}
|
|
130
|
+
return { index, frontmatter, slots };
|
|
128
131
|
}
|
|
129
132
|
export class FrontmatterParseError extends Error {
|
|
130
133
|
constructor(slideIndex, yamlSource, cause) {
|
|
@@ -185,12 +188,12 @@ function extractSlots(content) {
|
|
|
185
188
|
slotLines.get(currentSlot).push(line);
|
|
186
189
|
}
|
|
187
190
|
}
|
|
188
|
-
const
|
|
191
|
+
const leading = slotLines.get(null).join("\n").trim();
|
|
189
192
|
const slots = {};
|
|
190
193
|
for (const [name, sLines] of slotLines) {
|
|
191
194
|
if (name !== null) {
|
|
192
195
|
slots[name] = sLines.join("\n").trim();
|
|
193
196
|
}
|
|
194
197
|
}
|
|
195
|
-
return {
|
|
198
|
+
return { leading, slots };
|
|
196
199
|
}
|
package/dist/markdown/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RootContent } from "mdast";
|
|
2
|
-
import { type Frame, type ImageFill, type TableFill, type TemplateFill, type TextFill } from "../engine/index.js";
|
|
2
|
+
import { type BodyRows, type Frame, type ImageFill, type TableFill, type TemplateFill, type TextFill } from "../engine/index.js";
|
|
3
3
|
import type { MermaidConfig } from "./blocks/mermaidTheme.js";
|
|
4
|
+
export type { BodyRows };
|
|
4
5
|
/**
|
|
5
6
|
* An asset's scaling/cropping tolerance, declared in the theme catalog. The
|
|
6
7
|
* compiler maps it to the engine's object-fit `fit`. `icon`: never enlarge,
|
|
@@ -23,7 +24,6 @@ export type AssetEntry = {
|
|
|
23
24
|
/** Required — a missing type is a fail-fast error. */
|
|
24
25
|
type: AssetType;
|
|
25
26
|
description: string;
|
|
26
|
-
whenToUse?: string;
|
|
27
27
|
};
|
|
28
28
|
/** Two-level catalog: `{ category: { name: AssetEntry } }`. */
|
|
29
29
|
export type AssetCatalog = Record<string, Record<string, AssetEntry>>;
|
|
@@ -83,8 +83,8 @@ export type BlockFill = TextFill | TableFill | ImageFill;
|
|
|
83
83
|
* asset resolver, the diagnostic context to name the offending layout/slide/slot
|
|
84
84
|
* when a region's markdown shape is illegal (a stray standalone block mixed into
|
|
85
85
|
* prose), and the theme-level `config` — from which code/mermaid compile read
|
|
86
|
-
* their one-per-theme style (`codeTheme`, `mermaid`, `mermaidVariant
|
|
87
|
-
*
|
|
86
|
+
* their one-per-theme style (`codeTheme`, `mermaid`, `mermaidVariant`), not the
|
|
87
|
+
* slot.
|
|
88
88
|
*
|
|
89
89
|
* Lives in types.ts (not in `blocks/registry.ts`, which re-exports it) so a
|
|
90
90
|
* per-kind block file can import it without importing the registry — the registry
|
|
@@ -111,7 +111,7 @@ export type BlockContext = {
|
|
|
111
111
|
* build (`compile`) live together — a new content kind is one file, one registry
|
|
112
112
|
* row. Non-generic like the engine's `Filler`: the array can't correlate a
|
|
113
113
|
* per-element type guard with `compile`'s param, so each handler narrows the node
|
|
114
|
-
* internally with a single-hop cast.
|
|
114
|
+
* internally with a single-hop cast.
|
|
115
115
|
*/
|
|
116
116
|
export type BlockHandler = {
|
|
117
117
|
match(node: RootContent): boolean;
|
|
@@ -138,20 +138,10 @@ export type CompilerDeckStep = {
|
|
|
138
138
|
*/
|
|
139
139
|
export type CompilerDeck = {
|
|
140
140
|
theme: string;
|
|
141
|
+
/** Output path, set by the caller (the CLI, or a programmatic `buildDeck`), not from frontmatter. */
|
|
141
142
|
output?: string;
|
|
142
143
|
steps: CompilerDeckStep[];
|
|
143
144
|
};
|
|
144
|
-
/**
|
|
145
|
-
* Markdown-flavored measurement hints on a slot or template parameter: caps on
|
|
146
|
-
* expanded run text, line count, or list items. All optional — a missing cap is
|
|
147
|
-
* "no limit." Advisory metadata surfaced in the manifest; the fill never enforces
|
|
148
|
-
* it.
|
|
149
|
-
*/
|
|
150
|
-
export type Limit = {
|
|
151
|
-
maxChars?: number;
|
|
152
|
-
maxLines?: number;
|
|
153
|
-
maxItems?: number;
|
|
154
|
-
};
|
|
155
145
|
/**
|
|
156
146
|
* Template parameter: a styled text shape filled by expanding a `template` into the
|
|
157
147
|
* shape's paragraphs via fillTemplate. The template is one string with `{key}`
|
|
@@ -162,11 +152,11 @@ export type Limit = {
|
|
|
162
152
|
*/
|
|
163
153
|
export type CompilerTemplateParameter = {
|
|
164
154
|
shapeName: string;
|
|
165
|
-
limit?: Limit;
|
|
166
155
|
/**
|
|
167
156
|
* Whether the parameter may be omitted from a slide. Optional (defaults to
|
|
168
157
|
* false): a required one with no value causes the compiler to throw with
|
|
169
|
-
* layout + key names
|
|
158
|
+
* layout + key names; an optional one left unfilled has its shape removed
|
|
159
|
+
* from the slide.
|
|
170
160
|
*/
|
|
171
161
|
required?: boolean;
|
|
172
162
|
type: typeof ParameterType.Template;
|
|
@@ -174,14 +164,14 @@ export type CompilerTemplateParameter = {
|
|
|
174
164
|
template: string;
|
|
175
165
|
};
|
|
176
166
|
/** Image parameter: one frontmatter path filled by fillImage. Sizing/crop
|
|
177
|
-
* behaviour comes from the resolved asset's `type`, not the slot.
|
|
178
|
-
* `limit` — measuring an image path against char/line caps is meaningless. */
|
|
167
|
+
* behaviour comes from the resolved asset's `type`, not the slot. */
|
|
179
168
|
export type CompilerImageParameter = {
|
|
180
169
|
shapeName: string;
|
|
181
170
|
/**
|
|
182
171
|
* Whether the parameter may be omitted from a slide. Optional (defaults to
|
|
183
172
|
* false): a required one with no value causes the compiler to throw with
|
|
184
|
-
* layout + key names
|
|
173
|
+
* layout + key names; an optional one left unfilled has its shape removed
|
|
174
|
+
* from the slide.
|
|
185
175
|
*/
|
|
186
176
|
required?: boolean;
|
|
187
177
|
key: string;
|
|
@@ -193,63 +183,72 @@ export type CompilerImageParameter = {
|
|
|
193
183
|
*/
|
|
194
184
|
export type CompilerParameter = CompilerTemplateParameter | CompilerImageParameter;
|
|
195
185
|
/**
|
|
196
|
-
* Reserved keys in a deck's frontmatter — global (theme
|
|
197
|
-
* (layout
|
|
186
|
+
* Reserved keys in a deck's frontmatter — global (theme) and per-slide
|
|
187
|
+
* (layout). Exported so callers (e.g. cli.ts) reference the constants
|
|
198
188
|
* instead of literal strings.
|
|
199
189
|
*/
|
|
200
190
|
export declare const RESERVED_KEY: {
|
|
201
191
|
readonly LAYOUT: "layout";
|
|
202
|
-
readonly BODY: "body";
|
|
203
|
-
readonly OUTPUT: "output";
|
|
204
192
|
readonly THEME: "theme";
|
|
205
193
|
readonly NOTES: "notes";
|
|
206
194
|
};
|
|
207
195
|
/**
|
|
208
196
|
* A kind of content a slot accepts, and the real template shape that realizes
|
|
209
|
-
* it — the compiler mirror of the engine's `Block
|
|
210
|
-
* type (`text` | `table` | `image`)
|
|
211
|
-
*
|
|
197
|
+
* it — the compiler mirror of the engine's `Block`, a union discriminated by
|
|
198
|
+
* `type` (an engine content type: `text` | `table` | `image`) so each variant
|
|
199
|
+
* carries only its own specimen options. `shapeName` names the shape on
|
|
200
|
+
* `sourceSlide` carrying the specimen styling; when `sourceSlide` equals the
|
|
212
201
|
* layout's `slideNumber` the shape is already on the cloned slide (fill in
|
|
213
|
-
* place)
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
202
|
+
* place), otherwise it is transplanted into the slot's `frame`. A text block may
|
|
203
|
+
* pin `startAt` (leave the first N specimen paragraphs untouched); a table block
|
|
204
|
+
* MUST declare its `bodyRows` range (the repeatable `<a:tbl>` specimen rows); an
|
|
205
|
+
* image block carries neither. There is no `Template` variant — `AcceptType` excludes
|
|
206
|
+
* it (a parameter, not a body block). Named `CompilerBlock` to stay distinct from
|
|
207
|
+
* the engine's `Block` and the compiler's `BlockHandler`.
|
|
217
208
|
*/
|
|
218
|
-
export type
|
|
219
|
-
type: AcceptType;
|
|
209
|
+
export type CompilerTextBlock = {
|
|
210
|
+
type: typeof AcceptType.Text;
|
|
220
211
|
sourceSlide: number;
|
|
221
212
|
shapeName: string;
|
|
222
213
|
startAt?: number;
|
|
223
214
|
};
|
|
215
|
+
export type CompilerTableBlock = {
|
|
216
|
+
type: typeof AcceptType.Table;
|
|
217
|
+
sourceSlide: number;
|
|
218
|
+
shapeName: string;
|
|
219
|
+
bodyRows: BodyRows;
|
|
220
|
+
};
|
|
221
|
+
export type CompilerImageBlock = {
|
|
222
|
+
type: typeof AcceptType.Image;
|
|
223
|
+
sourceSlide: number;
|
|
224
|
+
shapeName: string;
|
|
225
|
+
};
|
|
226
|
+
export type CompilerBlock = CompilerTextBlock | CompilerTableBlock | CompilerImageBlock;
|
|
224
227
|
/**
|
|
225
|
-
* Compiler-facing slot. A layout's body region (
|
|
226
|
-
*
|
|
227
|
-
* `CompilerBlock`s and owns a `frame` (real observed EMU coordinates, never
|
|
228
|
+
* Compiler-facing slot. A layout's body region (a `::name::` region): it
|
|
229
|
+
* `accepts` a set of `CompilerBlock`s and owns a `frame` (real observed EMU coordinates, never
|
|
228
230
|
* computed). The author's markdown shape selects which accepted block a region
|
|
229
231
|
* routes to; a type the slot does not accept fails fast. `frame` is required
|
|
230
232
|
* only when a slot has a transplant block (a block whose `sourceSlide` differs
|
|
231
233
|
* from the layout's `slideNumber`); a base-only slot fills in place and needs
|
|
232
|
-
* none.
|
|
233
|
-
* Slot; per-slot `codeTheme` / `mermaidVariant` moved to the theme level.
|
|
234
|
+
* none.
|
|
234
235
|
*/
|
|
235
236
|
export type CompilerSlot = {
|
|
236
237
|
key: string;
|
|
237
238
|
accepts: CompilerBlock[];
|
|
238
239
|
frame?: Frame;
|
|
239
|
-
limit?: Limit;
|
|
240
240
|
/**
|
|
241
241
|
* Whether the slot may be omitted from a slide. Optional (defaults to false):
|
|
242
|
-
* a required slot with no content throws with layout + key names
|
|
242
|
+
* a required slot with no content throws with layout + key names; an optional
|
|
243
|
+
* slot left unfilled has its shape removed from the slide.
|
|
243
244
|
*/
|
|
244
245
|
required?: boolean;
|
|
245
246
|
};
|
|
246
247
|
export type CompilerLayout = {
|
|
247
248
|
name: string;
|
|
248
249
|
slideNumber: number;
|
|
249
|
-
/** Optional prose — a layout is a shape, not a purpose
|
|
250
|
+
/** Optional prose — a neutral description of the arrangement (a layout is a shape, not a purpose). */
|
|
250
251
|
description?: string;
|
|
251
|
-
whenToUse?: string;
|
|
252
|
-
whenNotToUse?: string;
|
|
253
252
|
/**
|
|
254
253
|
* The layout's tonal surface. Selects the arm of a `{ light, dark }` `codeTheme`
|
|
255
254
|
* pair for code fences on this layout. Required when `codeTheme` is a pair.
|
|
@@ -257,7 +256,7 @@ export type CompilerLayout = {
|
|
|
257
256
|
variant?: Variant;
|
|
258
257
|
/** Frontmatter inputs (template, image) — one value per `key: value` line. */
|
|
259
258
|
parameters: CompilerParameter[];
|
|
260
|
-
/** Body regions —
|
|
259
|
+
/** Body regions — `::name::` regions; each `accepts` blocks. */
|
|
261
260
|
slots: CompilerSlot[];
|
|
262
261
|
};
|
|
263
262
|
/**
|
|
@@ -286,7 +285,6 @@ export type CompilerThemeConfig = {
|
|
|
286
285
|
layouts: CompilerLayout[];
|
|
287
286
|
assets: AssetCatalog;
|
|
288
287
|
template: string;
|
|
289
|
-
outputDir?: string;
|
|
290
288
|
mermaid?: MermaidConfig;
|
|
291
289
|
/**
|
|
292
290
|
* Brand fonts injected as `@font-face` when rendering mermaid, so diagram text
|
package/dist/markdown/types.js
CHANGED
|
@@ -49,14 +49,12 @@ export const Variant = {
|
|
|
49
49
|
Dark: "dark",
|
|
50
50
|
};
|
|
51
51
|
/**
|
|
52
|
-
* Reserved keys in a deck's frontmatter — global (theme
|
|
53
|
-
* (layout
|
|
52
|
+
* Reserved keys in a deck's frontmatter — global (theme) and per-slide
|
|
53
|
+
* (layout). Exported so callers (e.g. cli.ts) reference the constants
|
|
54
54
|
* instead of literal strings.
|
|
55
55
|
*/
|
|
56
56
|
export const RESERVED_KEY = {
|
|
57
57
|
LAYOUT: "layout",
|
|
58
|
-
BODY: "body",
|
|
59
|
-
OUTPUT: "output",
|
|
60
58
|
THEME: "theme",
|
|
61
59
|
NOTES: "notes",
|
|
62
60
|
};
|
package/package.json
CHANGED
package/syntax.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
This document covers the detailed syntax for writing slide content in tycoslide deck files. For an overview of how to create slides, see [SKILL.md](SKILL.md).
|
|
4
4
|
|
|
5
|
+
> **Every layout, parameter, and slot name in the examples below is a placeholder.** Your theme's real names live in `manifest.json` — read it first, and never assume a name shown here (`Body`, `TwoColumn`, `hero`, `::left::`, etc.) exists in your theme.
|
|
6
|
+
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
## Global frontmatter
|
|
@@ -11,25 +13,27 @@ Every deck file starts with a global frontmatter block declaring the theme:
|
|
|
11
13
|
```markdown
|
|
12
14
|
---
|
|
13
15
|
theme: ./theme.json
|
|
14
|
-
output: my-deck.pptx
|
|
15
16
|
---
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
- **`theme`** (required) -- path to the theme config file, relative to the deck file.
|
|
19
|
-
|
|
20
|
+
|
|
21
|
+
The output `.pptx` is written next to the deck file, named after it (`deck.md` → `deck.pptx`).
|
|
20
22
|
|
|
21
23
|
---
|
|
22
24
|
|
|
23
|
-
## Body content
|
|
25
|
+
## Body content
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
A slide's body is split into named regions with `::name::` markers. Each region fills the slot whose key matches the marker name.
|
|
26
28
|
|
|
27
29
|
```markdown
|
|
28
30
|
---
|
|
29
|
-
layout: Body
|
|
31
|
+
layout: Body # ← placeholder; use a real layout from your manifest.json
|
|
30
32
|
title: Key Achievements
|
|
31
33
|
---
|
|
32
34
|
|
|
35
|
+
::body::
|
|
36
|
+
|
|
33
37
|
We exceeded targets across all metrics.
|
|
34
38
|
|
|
35
39
|
- Revenue up 23% quarter-over-quarter
|
|
@@ -37,9 +41,9 @@ We exceeded targets across all metrics.
|
|
|
37
41
|
- Three major product launches completed
|
|
38
42
|
```
|
|
39
43
|
|
|
40
|
-
Write
|
|
44
|
+
Write each region as paragraphs and bullets:
|
|
41
45
|
- `- ` starts a **bullet**; indent **2 spaces per level** to nest (` - ` = level 1).
|
|
42
|
-
- A line
|
|
46
|
+
- A line without a `- ` bullet is a **paragraph** (a lead-in / prose line).
|
|
43
47
|
- Blank lines are ignored (they're visual separators, not content).
|
|
44
48
|
- Do NOT put headings in body content -- the heading is the slide's `title` slot, and a subheading is the `subtitle` slot. Body is paragraphs + bullets only.
|
|
45
49
|
|
|
@@ -77,13 +81,13 @@ title: Before & After
|
|
|
77
81
|
- Zero-downtime deploys
|
|
78
82
|
```
|
|
79
83
|
|
|
80
|
-
Content
|
|
84
|
+
Content after a marker goes to the slot matching that name. The marker names must match the layout's slot keys.
|
|
81
85
|
|
|
82
86
|
---
|
|
83
87
|
|
|
84
88
|
## Parameters and slots (in `manifest.json`)
|
|
85
89
|
|
|
86
|
-
A layout advertises two kinds of author-facing input, split by one rule: **a parameter is one value on a frontmatter line; a slot is a multi-line region in the body** (
|
|
90
|
+
A layout advertises two kinds of author-facing input, split by one rule: **a parameter is one value on a frontmatter line; a slot is a multi-line region in the body** (a `::name::` region). In `manifest.json` each layout carries two lists, `parameters` and `slots`:
|
|
87
91
|
|
|
88
92
|
```jsonc
|
|
89
93
|
{
|
|
@@ -94,8 +98,8 @@ A layout advertises two kinds of author-facing input, split by one rule: **a par
|
|
|
94
98
|
{ "key": "logo", "type": "image", "required": true }
|
|
95
99
|
],
|
|
96
100
|
"slots": [
|
|
97
|
-
{ "key": "body", "
|
|
98
|
-
{ "key": "
|
|
101
|
+
{ "key": "body", "accepts": ["text"] },
|
|
102
|
+
{ "key": "diagram", "accepts": ["image"] }
|
|
99
103
|
]
|
|
100
104
|
}
|
|
101
105
|
```
|
|
@@ -119,13 +123,11 @@ Fill a parameter by putting a value under its key in the slide's frontmatter.
|
|
|
119
123
|
hero: assets/diagrams/architecture.png
|
|
120
124
|
```
|
|
121
125
|
|
|
122
|
-
###
|
|
126
|
+
### Body content shapes
|
|
123
127
|
|
|
124
|
-
Fill a slot by writing a region in the body
|
|
128
|
+
Fill a slot by writing a `::name::` region in the body; the marker maps to the slot of that name. A slot's manifest entry lists which content types it `accepts` (`text`, `table`, `image`) -- write content whose shape matches one of them:
|
|
125
129
|
|
|
126
|
-
-
|
|
127
|
-
- **`table`** -- a GFM table. Write it in the slot region between `|`-delimited headers and rows; cells inherit inline formatting (bold, italic, links).
|
|
128
|
-
- **`code`** -- a syntax-highlighted code block. Write a fenced code block with a language tag in the slot region:
|
|
130
|
+
- **text** (slots that accept `text`) -- markdown paragraphs and bullets, rebuilt from the template's specimen paragraph styles. A fenced code block also routes here:
|
|
129
131
|
````markdown
|
|
130
132
|
::code::
|
|
131
133
|
|
|
@@ -135,16 +137,15 @@ Fill a slot by writing a region in the body: the default (unmarked) region maps
|
|
|
135
137
|
WHERE created_at > now() - INTERVAL '5 minutes';
|
|
136
138
|
```
|
|
137
139
|
````
|
|
138
|
-
The language tag (e.g. `sql`, `python`, `typescript`) is required -- it drives syntax highlighting. Colors are applied as native text runs in the output, not images.
|
|
139
|
-
-
|
|
140
|
+
The language tag (e.g. `sql`, `python`, `typescript`) is required -- it drives syntax highlighting, using the theme's `codeTheme` (set once in `theme.json`, not per slot). Colors are applied as native text runs in the output, not images.
|
|
141
|
+
- **table** (slots that accept `table`) -- a GFM table. Write it in the slot region between `|`-delimited headers and rows; cells inherit inline formatting (bold, italic, links).
|
|
142
|
+
- **image** (slots that accept `image`) -- a picture. A fenced `mermaid` block renders to a themed PNG and fills it (see below).
|
|
140
143
|
|
|
141
144
|
---
|
|
142
145
|
|
|
143
146
|
## Mermaid diagrams
|
|
144
147
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
To let the same physical slide accept either an image or a diagram, the theme author declares two layouts with the same `slideNumber` -- one exposing the fill as an `image` parameter (frontmatter path), one as a `mermaid` slot (a fenced region). Authors pick between them by naming the layout in frontmatter; the compiler routes content based on the layout's declaration, so there is no ambiguity.
|
|
148
|
+
Write a fenced code block with the `mermaid` language tag in a named slot that accepts `image`. It renders to a themed PNG and behaves like any other image in the slot -- always shown in its entirety. The color variant comes from the theme's `mermaidVariant` (set once in `theme.json`, not per slot).
|
|
148
149
|
|
|
149
150
|
````markdown
|
|
150
151
|
---
|
|
@@ -212,13 +213,13 @@ hero: assets/diagrams/architecture.png
|
|
|
212
213
|
```
|
|
213
214
|
|
|
214
215
|
Each parameter or slot in the layout definition may declare:
|
|
215
|
-
- **`type`** (required) --
|
|
216
|
+
- **`type`** (parameters, required) -- `template` or `image`.
|
|
217
|
+
- **`accepts`** (slots, required) -- an array of `text`, `table`, `image`.
|
|
216
218
|
- **`required: true`** -- the slide has no usable default and the build fails if the parameter/slot has no value (e.g. team-member photos, icon-grid icons, the quote logo). If you don't have a suitable image, ask the user for one.
|
|
219
|
+
- **optional (the default)** -- a parameter or slot you leave unfilled is dropped from the slide (its shape is removed), so a layout with numbered slots (e.g. up to six sections, up to four stats) renders only the ones you fill.
|
|
217
220
|
- **image sizing** -- each catalog asset declares a `type` (`icon` | `image` | `background`) that determines how it is scaled and cropped: `icon` never enlarges past native and never crops; `image` fits the whole picture (no crop, may scale); `background` fills and center-crops. Mermaid renders as `image` (contained).
|
|
218
|
-
- **`codeTheme`** -- code slots only (required): the Shiki theme id used to syntax-highlight fenced code that lands in this slot (e.g. `"github-dark"`).
|
|
219
|
-
- **`mermaidVariant`** -- mermaid slots only (required): names the color variant from `theme.mermaid` (e.g. `"dark"`). See [Mermaid diagrams](#mermaid-diagrams) above.
|
|
220
221
|
|
|
221
|
-
Each layout also declares a `slideNumber` pointing at the physical slide in the theme's template
|
|
222
|
+
Each layout also declares a `slideNumber` pointing at the physical slide in the theme's template -- unique per layout (one layout maps to one physical slide).
|
|
222
223
|
|
|
223
224
|
---
|
|
224
225
|
|
|
@@ -274,6 +275,8 @@ layout: Body
|
|
|
274
275
|
title: Your First Week
|
|
275
276
|
---
|
|
276
277
|
|
|
278
|
+
::body::
|
|
279
|
+
|
|
277
280
|
Here is what to expect in your first week.
|
|
278
281
|
|
|
279
282
|
- Day 1: Laptop setup and HR orientation
|