mulmocast 2.6.15 → 2.6.17

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.
Files changed (65) hide show
  1. package/lib/actions/index.d.ts +1 -0
  2. package/lib/actions/index.js +1 -0
  3. package/lib/actions/viewer.d.ts +3 -0
  4. package/lib/actions/viewer.js +173 -0
  5. package/lib/cli/bin.js +0 -0
  6. package/lib/cli/commands/viewer/builder.d.ts +20 -0
  7. package/lib/cli/commands/viewer/builder.js +6 -0
  8. package/lib/cli/commands/viewer/handler.d.ts +4 -0
  9. package/lib/cli/commands/viewer/handler.js +11 -0
  10. package/lib/cli/commands/viewer/index.d.ts +4 -0
  11. package/lib/cli/commands/viewer/index.js +4 -0
  12. package/lib/cli/main.js +2 -0
  13. package/lib/mcp/server.js +0 -0
  14. package/lib/types/schema.d.ts +458 -457
  15. package/lib/types/schema.js +3 -2
  16. package/lib/types/type.d.ts +1 -1
  17. package/lib/utils/context.d.ts +729 -728
  18. package/lib/utils/context.js +1 -0
  19. package/lib/utils/image_plugins/slide.d.ts +1 -1
  20. package/lib/utils/image_plugins/slide.js +1 -1
  21. package/package.json +12 -11
  22. package/lib/data/styles.d.ts +0 -255
  23. package/lib/data/styles.js +0 -284
  24. package/lib/slide/blocks.d.ts +0 -13
  25. package/lib/slide/blocks.js +0 -251
  26. package/lib/slide/index.d.ts +0 -6
  27. package/lib/slide/index.js +0 -7
  28. package/lib/slide/layouts/big_quote.d.ts +0 -2
  29. package/lib/slide/layouts/big_quote.js +0 -19
  30. package/lib/slide/layouts/columns.d.ts +0 -2
  31. package/lib/slide/layouts/columns.js +0 -53
  32. package/lib/slide/layouts/comparison.d.ts +0 -2
  33. package/lib/slide/layouts/comparison.js +0 -25
  34. package/lib/slide/layouts/funnel.d.ts +0 -2
  35. package/lib/slide/layouts/funnel.js +0 -25
  36. package/lib/slide/layouts/grid.d.ts +0 -2
  37. package/lib/slide/layouts/grid.js +0 -38
  38. package/lib/slide/layouts/index.d.ts +0 -3
  39. package/lib/slide/layouts/index.js +0 -46
  40. package/lib/slide/layouts/matrix.d.ts +0 -2
  41. package/lib/slide/layouts/matrix.js +0 -53
  42. package/lib/slide/layouts/split.d.ts +0 -2
  43. package/lib/slide/layouts/split.js +0 -51
  44. package/lib/slide/layouts/stats.d.ts +0 -2
  45. package/lib/slide/layouts/stats.js +0 -23
  46. package/lib/slide/layouts/table.d.ts +0 -2
  47. package/lib/slide/layouts/table.js +0 -10
  48. package/lib/slide/layouts/timeline.d.ts +0 -2
  49. package/lib/slide/layouts/timeline.js +0 -27
  50. package/lib/slide/layouts/title.d.ts +0 -2
  51. package/lib/slide/layouts/title.js +0 -19
  52. package/lib/slide/layouts/waterfall.d.ts +0 -2
  53. package/lib/slide/layouts/waterfall.js +0 -63
  54. package/lib/slide/render.d.ts +0 -17
  55. package/lib/slide/render.js +0 -101
  56. package/lib/slide/schema.d.ts +0 -9309
  57. package/lib/slide/schema.js +0 -434
  58. package/lib/slide/utils.d.ts +0 -76
  59. package/lib/slide/utils.js +0 -243
  60. package/lib/types/slide.d.ts +0 -9309
  61. package/lib/types/slide.js +0 -434
  62. package/lib/utils/browser_pool.d.ts +0 -5
  63. package/lib/utils/browser_pool.js +0 -39
  64. package/lib/utils/markdown.d.ts +0 -3
  65. package/lib/utils/markdown.js +0 -49
@@ -1,251 +0,0 @@
1
- import { escapeHtml, c, generateSlideId, renderInlineMarkup, blockTitle, resolveChangeColor, resolveAccent } from "./utils.js";
2
- // ─── Table cell rendering (shared with layouts/table.ts) ───
3
- export const resolveCellColor = (cellObj, isRowHeader) => {
4
- if (cellObj.color)
5
- return `text-${c(cellObj.color)}`;
6
- if (isRowHeader)
7
- return "text-d-text";
8
- return "text-d-muted";
9
- };
10
- export const renderBadge = (text, color) => {
11
- return `<span class="px-2 py-0.5 rounded-full text-xs font-bold text-white bg-${c(color)}">${renderInlineMarkup(text)}</span>`;
12
- };
13
- export const renderCellValue = (cell, isRowHeader) => {
14
- const cellObj = typeof cell === "object" && cell !== null ? cell : { text: String(cell) };
15
- if (cellObj.badge && cellObj.color) {
16
- return `<td class="px-4 py-3 text-sm font-body border-b border-d-alt">${renderBadge(cellObj.text, cellObj.color)}</td>`;
17
- }
18
- const colorCls = resolveCellColor(cellObj, isRowHeader);
19
- const boldCls = cellObj.bold || isRowHeader ? "font-bold" : "";
20
- return `<td class="px-4 py-3 text-sm ${colorCls} ${boldCls} font-body border-b border-d-alt">${renderInlineMarkup(cellObj.text)}</td>`;
21
- };
22
- export const renderTableCore = (headers, rows, rowHeaders, striped) => {
23
- const parts = [];
24
- const isStriped = striped !== false;
25
- parts.push(`<table class="w-full border-collapse">`);
26
- if (headers && headers.length > 0) {
27
- parts.push(`<thead>`);
28
- parts.push(`<tr>`);
29
- headers.forEach((h) => {
30
- parts.push(` <th class="text-left px-4 py-3 text-sm font-bold text-d-text font-body border-b-2 border-d-alt">${renderInlineMarkup(h)}</th>`);
31
- });
32
- parts.push(`</tr>`);
33
- parts.push(`</thead>`);
34
- }
35
- parts.push(`<tbody>`);
36
- rows.forEach((row, ri) => {
37
- const bgCls = isStriped && ri % 2 === 1 ? "bg-d-alt/30" : "";
38
- parts.push(`<tr class="${bgCls}">`);
39
- (row || []).forEach((cell, ci) => {
40
- const isRowHeader = ci === 0 && !!rowHeaders;
41
- parts.push(` ${renderCellValue(cell, isRowHeader)}`);
42
- });
43
- parts.push(`</tr>`);
44
- });
45
- parts.push(`</tbody>`);
46
- parts.push(`</table>`);
47
- return parts.join("\n");
48
- };
49
- const renderTableBlock = (block) => {
50
- return `<div class="overflow-auto">${blockTitle(block.title)}${renderTableCore(block.headers, block.rows, block.rowHeaders, block.striped)}</div>`;
51
- };
52
- /** Render a single content block to HTML */
53
- export const renderContentBlock = (block) => {
54
- switch (block.type) {
55
- case "text":
56
- return renderText(block);
57
- case "bullets":
58
- return renderBullets(block);
59
- case "code":
60
- return renderCode(block);
61
- case "callout":
62
- return renderCallout(block);
63
- case "metric":
64
- return renderMetric(block);
65
- case "divider":
66
- return renderDivider(block);
67
- case "image":
68
- return renderImage(block);
69
- case "imageRef":
70
- return renderImageRefPlaceholder(block);
71
- case "chart":
72
- return renderChart(block);
73
- case "mermaid":
74
- return renderMermaid(block);
75
- case "section":
76
- return renderSection(block);
77
- case "table":
78
- return renderTableBlock(block);
79
- default:
80
- return `<p class="text-sm text-d-muted font-body">[unknown block type]</p>`;
81
- }
82
- };
83
- /** Render an array of content blocks to HTML */
84
- export const renderContentBlocks = (blocks) => {
85
- return blocks.map(renderContentBlock).join("\n");
86
- };
87
- /** Render content blocks with fixed aspect-ratio container for image blocks (used in card layouts) */
88
- export const renderCardContentBlocks = (blocks) => {
89
- return blocks
90
- .map((block) => {
91
- if (block.type === "image") {
92
- return `<div class="aspect-video shrink-0 overflow-hidden">${renderContentBlock(block)}</div>`;
93
- }
94
- return renderContentBlock(block);
95
- })
96
- .join("\n");
97
- };
98
- const resolveTextColor = (block) => {
99
- if (block.color)
100
- return `text-${c(block.color)}`;
101
- if (block.dim)
102
- return "text-d-dim";
103
- return "text-d-muted";
104
- };
105
- const resolveAlign = (align) => {
106
- if (align === "center")
107
- return "text-center";
108
- if (align === "right")
109
- return "text-right";
110
- return "";
111
- };
112
- const renderText = (block) => {
113
- const color = resolveTextColor(block);
114
- const bold = block.bold ? "font-bold" : "";
115
- const size = block.fontSize !== undefined && block.fontSize >= 18 ? "text-xl" : "text-[15px]";
116
- const alignCls = resolveAlign(block.align);
117
- return `<p class="${size} ${color} ${bold} ${alignCls} font-body leading-relaxed">${renderInlineMarkup(block.value)}</p>`;
118
- };
119
- /** Extract text from a bullet item (string or object) */
120
- const bulletItemText = (item) => {
121
- return typeof item === "string" ? item : item.text;
122
- };
123
- /** Render sub-bullets for a nested bullet item */
124
- const renderSubBullets = (item) => {
125
- if (typeof item === "string" || !item.items || item.items.length === 0)
126
- return "";
127
- const subs = item.items
128
- .map((sub) => {
129
- return ` <li class="flex gap-2 ml-6 text-[14px]"><span class="text-d-dim shrink-0">\u25E6</span><span>${renderInlineMarkup(bulletItemText(sub))}</span></li>`;
130
- })
131
- .join("\n");
132
- return `\n${subs}`;
133
- };
134
- const renderBullets = (block) => {
135
- const tag = block.ordered ? "ol" : "ul";
136
- const items = block.items
137
- .map((item, i) => {
138
- const marker = block.ordered ? `${i + 1}.` : escapeHtml(block.icon || "\u2022");
139
- const text = bulletItemText(item);
140
- const subHtml = renderSubBullets(item);
141
- return ` <li class="flex flex-col gap-1"><div class="flex gap-2"><span class="text-d-dim shrink-0">${marker}</span><span>${renderInlineMarkup(text)}</span></div>${subHtml}</li>`;
142
- })
143
- .join("\n");
144
- return `<${tag} class="space-y-2 text-[15px] text-d-muted font-body">\n${items}\n</${tag}>`;
145
- };
146
- const renderCode = (block) => {
147
- return `<pre class="bg-[#0D1117] p-4 rounded text-sm font-mono text-d-dim leading-relaxed whitespace-pre-wrap">${escapeHtml(block.code)}</pre>`;
148
- };
149
- const renderCallout = (block) => {
150
- const isQuote = block.style === "quote";
151
- const resolveBorderCls = (style) => {
152
- if (style === "warning")
153
- return `border-l-2 border-${c("warning")}`;
154
- if (style === "info")
155
- return `border-l-2 border-${c("info")}`;
156
- return "";
157
- };
158
- const borderCls = resolveBorderCls(block.style);
159
- const bg = isQuote ? "bg-d-alt" : "bg-d-card";
160
- const textCls = isQuote ? "italic text-d-muted" : "text-d-muted";
161
- const content = block.label
162
- ? `<span class="font-bold text-${c(block.color || "warning")}">${renderInlineMarkup(block.label)}:</span> <span class="text-d-muted">${renderInlineMarkup(block.text)}</span>`
163
- : `<span class="${textCls}">${renderInlineMarkup(block.text)}</span>`;
164
- return `<div class="${bg} ${borderCls} p-3 rounded text-sm font-body">${content}</div>`;
165
- };
166
- const renderMetric = (block) => {
167
- const lines = [];
168
- lines.push(`<div class="text-center">`);
169
- lines.push(` <p class="text-4xl font-bold text-${c(resolveAccent(block.color))}">${renderInlineMarkup(block.value)}</p>`);
170
- lines.push(` <p class="text-sm text-d-dim mt-1">${renderInlineMarkup(block.label)}</p>`);
171
- if (block.change) {
172
- lines.push(` <p class="text-sm font-bold text-${c(resolveChangeColor(block.change))} mt-1">${escapeHtml(block.change)}</p>`);
173
- }
174
- lines.push(`</div>`);
175
- return lines.join("\n");
176
- };
177
- const renderDivider = (block) => {
178
- const divColor = block.color ? `bg-${c(block.color)}` : "bg-d-alt";
179
- return `<div class="h-[2px] ${divColor} my-2 rounded-full"></div>`;
180
- };
181
- const renderImage = (block) => {
182
- const fit = block.fit === "cover" ? "object-cover" : "object-contain";
183
- return `<div class="min-h-0 flex-1 overflow-hidden flex items-center"><img src="${escapeHtml(block.src)}" alt="${escapeHtml(block.alt || "")}" class="rounded ${fit} w-full h-full" /></div>`;
184
- };
185
- /** Placeholder for unresolved imageRef blocks — should be resolved before rendering */
186
- const renderImageRefPlaceholder = (block) => {
187
- return `<div class="min-h-0 flex-1 overflow-hidden flex items-center justify-center bg-d-alt rounded"><p class="text-sm text-d-dim font-body">[imageRef: ${escapeHtml(block.ref)}]</p></div>`;
188
- };
189
- const renderChart = (block) => {
190
- const chartId = generateSlideId("chart");
191
- const chartData = JSON.stringify(block.chartData);
192
- return `<div class="flex-1 min-h-0 flex flex-col">
193
- ${blockTitle(block.title)}
194
- <div class="flex-1 min-h-0 relative">
195
- <canvas id="${chartId}" data-chart-ready="false"></canvas>
196
- </div>
197
- <script>(function(){
198
- const ctx=document.getElementById('${chartId}');
199
- const d=${chartData};
200
- if(!d.options)d.options={};
201
- d.options.animation=false;
202
- d.options.responsive=true;
203
- d.options.maintainAspectRatio=false;
204
- new Chart(ctx,d);
205
- requestAnimationFrame(()=>requestAnimationFrame(()=>{ctx.dataset.chartReady="true"}));
206
- })()</script>
207
- </div>`;
208
- };
209
- const renderMermaid = (block) => {
210
- const mermaidId = generateSlideId("mermaid");
211
- return `<div class="flex-1 min-h-0 flex flex-col">
212
- ${blockTitle(block.title)}
213
- <div class="flex-1 min-h-0 flex justify-center items-center">
214
- <div id="${mermaidId}" class="mermaid">${escapeHtml(block.code)}</div>
215
- </div>
216
- </div>`;
217
- };
218
- /** Render the text + content blocks inside a section (shared by sidebar/default variants) */
219
- const renderSectionContent = (block) => {
220
- const parts = [];
221
- if (block.text) {
222
- parts.push(`<p class="text-[15px] text-d-muted font-body">${renderInlineMarkup(block.text)}</p>`);
223
- }
224
- if (block.content) {
225
- parts.push(block.content.map(renderContentBlock).join("\n"));
226
- }
227
- return parts.join("\n");
228
- };
229
- const renderSectionSidebar = (block) => {
230
- const color = resolveAccent(block.color);
231
- const chars = block.label
232
- .split("")
233
- .map((ch) => escapeHtml(ch))
234
- .join("<br>");
235
- const sidebar = `<div class="w-[48px] shrink-0 rounded-l bg-${c(color)} flex items-center justify-center"><span class="text-sm font-bold text-white font-body leading-snug text-center">${chars}</span></div>`;
236
- return `<div class="flex rounded overflow-hidden bg-d-card">
237
- ${sidebar}
238
- <div class="flex-1 space-y-2 p-3">${renderSectionContent(block)}</div>
239
- </div>`;
240
- };
241
- const renderSectionDefault = (block) => {
242
- const color = resolveAccent(block.color);
243
- const badge = `<span class="min-w-[80px] px-3 py-1 rounded text-sm font-bold text-white bg-${c(color)} shrink-0">${renderInlineMarkup(block.label)}</span>`;
244
- return `<div class="flex gap-4 items-start">
245
- ${badge}
246
- <div class="flex-1 space-y-2">${renderSectionContent(block)}</div>
247
- </div>`;
248
- };
249
- const renderSection = (block) => {
250
- return block.sidebar ? renderSectionSidebar(block) : renderSectionDefault(block);
251
- };
@@ -1,6 +0,0 @@
1
- export { generateSlideHTML } from "./render.js";
2
- export type { ResolvedBranding } from "./render.js";
3
- export { renderSlideContent } from "./layouts/index.js";
4
- export { renderContentBlock, renderContentBlocks } from "./blocks.js";
5
- export { mulmoSlideMediaSchema, slideLayoutSchema, slideThemeSchema, contentBlockSchema, imageRefBlockSchema, chartBlockSchema, mermaidBlockSchema, accentColorKeySchema, slideBrandingLogoSchema, slideBrandingSchema, } from "./schema.js";
6
- export type { MulmoSlideMedia, SlideLayout, SlideTheme, SlideThemeColors, SlideThemeFonts, ContentBlock, ImageRefBlock, ChartBlock, MermaidBlock, AccentColorKey, TitleSlide, ColumnsSlide, ComparisonSlide, GridSlide, BigQuoteSlide, StatsSlide, TimelineSlide, SplitSlide, MatrixSlide, TableSlide, FunnelSlide, Card, CalloutBar, SlideStyle, SlideBrandingLogo, SlideBranding, } from "./schema.js";
@@ -1,7 +0,0 @@
1
- // Public API for the slide module
2
- // This module is self-contained and can be extracted into a standalone package
3
- export { generateSlideHTML } from "./render.js";
4
- export { renderSlideContent } from "./layouts/index.js";
5
- export { renderContentBlock, renderContentBlocks } from "./blocks.js";
6
- // Schemas
7
- export { mulmoSlideMediaSchema, slideLayoutSchema, slideThemeSchema, contentBlockSchema, imageRefBlockSchema, chartBlockSchema, mermaidBlockSchema, accentColorKeySchema, slideBrandingLogoSchema, slideBrandingSchema, } from "./schema.js";
@@ -1,2 +0,0 @@
1
- import type { BigQuoteSlide } from "../schema.js";
2
- export declare const layoutBigQuote: (data: BigQuoteSlide) => string;
@@ -1,19 +0,0 @@
1
- import { renderInlineMarkup, accentBar, resolveAccent } from "../utils.js";
2
- export const layoutBigQuote = (data) => {
3
- const accent = resolveAccent(data.accentColor);
4
- const parts = [];
5
- parts.push(`<div class="flex flex-col items-center justify-center h-full px-20">`);
6
- parts.push(` ${accentBar(accent, "w-24 mb-8")}`);
7
- parts.push(` <blockquote class="text-[32px] text-d-text font-title italic text-center leading-relaxed">`);
8
- parts.push(` &ldquo;${renderInlineMarkup(data.quote)}&rdquo;`);
9
- parts.push(` </blockquote>`);
10
- parts.push(` ${accentBar(accent, "w-24 mt-8 mb-6")}`);
11
- if (data.author) {
12
- parts.push(` <p class="text-lg text-d-muted font-body">${renderInlineMarkup(data.author)}</p>`);
13
- }
14
- if (data.role) {
15
- parts.push(` <p class="text-sm text-d-dim font-body mt-1">${renderInlineMarkup(data.role)}</p>`);
16
- }
17
- parts.push(`</div>`);
18
- return parts.join("\n");
19
- };
@@ -1,2 +0,0 @@
1
- import type { ColumnsSlide } from "../schema.js";
2
- export declare const layoutColumns: (data: ColumnsSlide) => string;
@@ -1,53 +0,0 @@
1
- import { renderInlineMarkup, c, cardWrap, numBadge, iconSquare, slideHeader, renderOptionalCallout, resolveAccent } from "../utils.js";
2
- import { renderCardContentBlocks } from "../blocks.js";
3
- const buildColumnCard = (col) => {
4
- const accent = resolveAccent(col.accentColor);
5
- const inner = [];
6
- if (col.icon) {
7
- inner.push(`<div class="flex flex-col items-center mb-3">`);
8
- inner.push(` ${iconSquare(col.icon, accent)}`);
9
- inner.push(`</div>`);
10
- inner.push(`<h3 class="text-lg font-bold text-d-text text-center font-body">${renderInlineMarkup(col.title)}</h3>`);
11
- }
12
- else if (col.num != null) {
13
- inner.push(`<div class="flex items-center gap-3 mb-1">`);
14
- inner.push(` ${numBadge(col.num, accent)}`);
15
- inner.push(` <h3 class="text-lg font-bold text-d-text font-body">${renderInlineMarkup(col.title)}</h3>`);
16
- inner.push(`</div>`);
17
- }
18
- else {
19
- if (col.label) {
20
- inner.push(`<p class="text-sm font-bold text-${c(accent)} font-body">${renderInlineMarkup(col.label)}</p>`);
21
- }
22
- inner.push(`<h3 class="text-2xl font-title font-bold text-d-text mt-1">${renderInlineMarkup(col.title)}</h3>`);
23
- }
24
- if (col.content) {
25
- const centerCls = col.icon ? "text-center" : "";
26
- inner.push(`<div class="mt-4 space-y-4 flex-1 min-h-0 overflow-auto flex flex-col ${centerCls}">`);
27
- inner.push(renderCardContentBlocks(col.content));
28
- inner.push(`</div>`);
29
- }
30
- if (col.footer) {
31
- inner.push(`<p class="text-sm text-d-dim font-body mt-auto pt-3">${renderInlineMarkup(col.footer)}</p>`);
32
- }
33
- return cardWrap(accent, inner.join("\n"), "flex-1");
34
- };
35
- export const layoutColumns = (data) => {
36
- const cols = data.columns || [];
37
- const parts = [slideHeader(data)];
38
- const colElements = [];
39
- cols.forEach((col, i) => {
40
- colElements.push(buildColumnCard(col));
41
- if (data.showArrows && i < cols.length - 1) {
42
- colElements.push(`<div class="flex items-center shrink-0"><span class="text-2xl text-d-dim">\u25B6</span></div>`);
43
- }
44
- });
45
- parts.push(`<div class="flex gap-4 px-12 mt-5 flex-1 min-h-0 items-start">`);
46
- parts.push(colElements.join("\n"));
47
- parts.push(`</div>`);
48
- parts.push(renderOptionalCallout(data.callout));
49
- if (data.bottomText) {
50
- parts.push(`<p class="text-center text-sm text-d-dim font-body pb-4">${renderInlineMarkup(data.bottomText)}</p>`);
51
- }
52
- return parts.join("\n");
53
- };
@@ -1,2 +0,0 @@
1
- import type { ComparisonSlide } from "../schema.js";
2
- export declare const layoutComparison: (data: ComparisonSlide) => string;
@@ -1,25 +0,0 @@
1
- import { renderInlineMarkup, c, cardWrap, slideHeader, renderOptionalCallout, resolveAccent } from "../utils.js";
2
- import { renderContentBlocks } from "../blocks.js";
3
- const buildPanel = (panel) => {
4
- const accent = resolveAccent(panel.accentColor);
5
- const inner = [];
6
- inner.push(`<h3 class="text-xl font-bold text-${c(accent)} font-body">${renderInlineMarkup(panel.title)}</h3>`);
7
- if (panel.content) {
8
- inner.push(`<div class="mt-5 space-y-4 flex-1 min-h-0 overflow-auto flex flex-col">`);
9
- inner.push(renderContentBlocks(panel.content));
10
- inner.push(`</div>`);
11
- }
12
- if (panel.footer) {
13
- inner.push(`<p class="text-sm text-d-dim font-body mt-auto pt-3">${renderInlineMarkup(panel.footer)}</p>`);
14
- }
15
- return cardWrap(accent, inner.join("\n"), "flex-1");
16
- };
17
- export const layoutComparison = (data) => {
18
- const parts = [slideHeader(data)];
19
- parts.push(`<div class="flex gap-5 px-12 mt-5 flex-1 min-h-0 items-start">`);
20
- parts.push(buildPanel(data.left));
21
- parts.push(buildPanel(data.right));
22
- parts.push(`</div>`);
23
- parts.push(renderOptionalCallout(data.callout));
24
- return parts.join("\n");
25
- };
@@ -1,2 +0,0 @@
1
- import type { FunnelSlide } from "../schema.js";
2
- export declare const layoutFunnel: (data: FunnelSlide) => string;
@@ -1,25 +0,0 @@
1
- import { renderInlineMarkup, c, slideHeader, renderOptionalCallout, resolveItemColor } from "../utils.js";
2
- export const layoutFunnel = (data) => {
3
- const parts = [slideHeader(data)];
4
- const stages = data.stages || [];
5
- const total = stages.length;
6
- parts.push(`<div class="flex flex-col items-center gap-2 px-12 mt-6 flex-1">`);
7
- stages.forEach((stage, i) => {
8
- const color = resolveItemColor(stage.color, data.accentColor);
9
- const widthPct = 100 - (i / Math.max(total - 1, 1)) * 55;
10
- parts.push(`<div class="bg-${c(color)} rounded-lg flex items-center justify-between px-6 py-4" style="width: ${widthPct}%">`);
11
- parts.push(` <div class="flex items-center gap-3">`);
12
- parts.push(` <span class="text-base font-bold text-white font-body">${renderInlineMarkup(stage.label)}</span>`);
13
- if (stage.description) {
14
- parts.push(` <span class="text-sm text-white/70 font-body">${renderInlineMarkup(stage.description)}</span>`);
15
- }
16
- parts.push(` </div>`);
17
- if (stage.value) {
18
- parts.push(` <span class="text-lg font-bold text-white font-body">${renderInlineMarkup(stage.value)}</span>`);
19
- }
20
- parts.push(`</div>`);
21
- });
22
- parts.push(`</div>`);
23
- parts.push(renderOptionalCallout(data.callout));
24
- return parts.join("\n");
25
- };
@@ -1,2 +0,0 @@
1
- import type { GridSlide } from "../schema.js";
2
- export declare const layoutGrid: (data: GridSlide) => string;
@@ -1,38 +0,0 @@
1
- import { renderInlineMarkup, cardWrap, numBadge, iconSquare, slideHeader, resolveAccent } from "../utils.js";
2
- import { renderCardContentBlocks } from "../blocks.js";
3
- export const layoutGrid = (data) => {
4
- const nCols = data.gridColumns || 3;
5
- const parts = [slideHeader(data)];
6
- parts.push(`<div class="grid grid-cols-${nCols} gap-4 px-12 mt-5 flex-1 min-h-0 overflow-hidden content-center">`);
7
- (data.items || []).forEach((item) => {
8
- const itemAccent = resolveAccent(item.accentColor);
9
- const inner = [];
10
- if (item.icon) {
11
- inner.push(`<div class="flex flex-col items-center mb-2">`);
12
- inner.push(` ${iconSquare(item.icon, itemAccent)}`);
13
- inner.push(`</div>`);
14
- inner.push(`<h3 class="text-lg font-bold text-d-text text-center font-body">${renderInlineMarkup(item.title)}</h3>`);
15
- }
16
- else if (item.num != null) {
17
- inner.push(`<div class="flex items-center gap-3">`);
18
- inner.push(` ${numBadge(item.num, itemAccent)}`);
19
- inner.push(` <h3 class="text-sm font-bold text-d-text font-body">${renderInlineMarkup(item.title)}</h3>`);
20
- inner.push(`</div>`);
21
- }
22
- else {
23
- inner.push(`<h3 class="text-lg font-bold text-d-text font-body">${renderInlineMarkup(item.title)}</h3>`);
24
- }
25
- if (item.description) {
26
- inner.push(`<p class="text-sm text-d-muted font-body mt-3">${renderInlineMarkup(item.description)}</p>`);
27
- }
28
- if (item.content) {
29
- inner.push(`<div class="mt-3 space-y-3 flex-1 min-h-0 overflow-hidden flex flex-col">${renderCardContentBlocks(item.content)}</div>`);
30
- }
31
- parts.push(cardWrap(itemAccent, inner.join("\n")));
32
- });
33
- parts.push(`</div>`);
34
- if (data.footer) {
35
- parts.push(`<p class="text-xs text-d-dim font-body px-12 pb-3">${renderInlineMarkup(data.footer)}</p>`);
36
- }
37
- return parts.join("\n");
38
- };
@@ -1,3 +0,0 @@
1
- import type { SlideLayout } from "../schema.js";
2
- /** Render the inner content of a slide (without the wrapper div) */
3
- export declare const renderSlideContent: (slide: SlideLayout) => string;
@@ -1,46 +0,0 @@
1
- import { layoutTitle } from "./title.js";
2
- import { layoutColumns } from "./columns.js";
3
- import { layoutComparison } from "./comparison.js";
4
- import { layoutGrid } from "./grid.js";
5
- import { layoutBigQuote } from "./big_quote.js";
6
- import { layoutStats } from "./stats.js";
7
- import { layoutTimeline } from "./timeline.js";
8
- import { layoutSplit } from "./split.js";
9
- import { layoutMatrix } from "./matrix.js";
10
- import { layoutTable } from "./table.js";
11
- import { layoutFunnel } from "./funnel.js";
12
- import { layoutWaterfall } from "./waterfall.js";
13
- import { escapeHtml } from "../utils.js";
14
- /** Render the inner content of a slide (without the wrapper div) */
15
- export const renderSlideContent = (slide) => {
16
- switch (slide.layout) {
17
- case "title":
18
- return layoutTitle(slide);
19
- case "columns":
20
- return layoutColumns(slide);
21
- case "comparison":
22
- return layoutComparison(slide);
23
- case "grid":
24
- return layoutGrid(slide);
25
- case "bigQuote":
26
- return layoutBigQuote(slide);
27
- case "stats":
28
- return layoutStats(slide);
29
- case "timeline":
30
- return layoutTimeline(slide);
31
- case "split":
32
- return layoutSplit(slide);
33
- case "matrix":
34
- return layoutMatrix(slide);
35
- case "table":
36
- return layoutTable(slide);
37
- case "funnel":
38
- return layoutFunnel(slide);
39
- case "waterfall":
40
- return layoutWaterfall(slide);
41
- default: {
42
- const _exhaustive = slide;
43
- return `<p class="text-white p-8">Unknown layout: ${escapeHtml(String(_exhaustive.layout))}</p>`;
44
- }
45
- }
46
- };
@@ -1,2 +0,0 @@
1
- import type { MatrixSlide } from "../schema.js";
2
- export declare const layoutMatrix: (data: MatrixSlide) => string;
@@ -1,53 +0,0 @@
1
- import { renderInlineMarkup, c, cardWrap, slideHeader, resolveAccent } from "../utils.js";
2
- import { renderContentBlocks } from "../blocks.js";
3
- export const layoutMatrix = (data) => {
4
- const parts = [slideHeader(data)];
5
- const rows = data.rows || 2;
6
- const cols = data.cols || 2;
7
- const cells = data.cells || [];
8
- parts.push(`<div class="flex flex-1 px-12 mt-4 gap-2">`);
9
- if (data.yAxis) {
10
- parts.push(`<div class="flex flex-col justify-between items-center w-6 shrink-0 py-4">`);
11
- parts.push(` <span class="text-xs text-d-dim font-body [writing-mode:vertical-lr] rotate-180">${renderInlineMarkup(data.yAxis.high || "")}</span>`);
12
- if (data.yAxis.label) {
13
- parts.push(` <span class="text-xs font-bold text-d-muted font-body [writing-mode:vertical-lr] rotate-180">${renderInlineMarkup(data.yAxis.label)}</span>`);
14
- }
15
- parts.push(` <span class="text-xs text-d-dim font-body [writing-mode:vertical-lr] rotate-180">${renderInlineMarkup(data.yAxis.low || "")}</span>`);
16
- parts.push(`</div>`);
17
- }
18
- parts.push(`<div class="flex-1 flex flex-col gap-3">`);
19
- Array.from({ length: rows }).forEach((_row, r) => {
20
- parts.push(`<div class="flex gap-3 flex-1">`);
21
- Array.from({ length: cols }).forEach((_col, ci) => {
22
- const idx = r * cols + ci;
23
- const cell = cells[idx] || { label: "" };
24
- const accent = resolveAccent(cell.accentColor);
25
- const inner = [];
26
- inner.push(`<h3 class="text-lg font-bold text-${c(accent)} font-body">${renderInlineMarkup(cell.label)}</h3>`);
27
- if (cell.items) {
28
- inner.push(`<ul class="mt-2 space-y-1 text-sm text-d-muted font-body">`);
29
- cell.items.forEach((item) => {
30
- inner.push(` <li class="flex gap-2"><span class="text-d-dim shrink-0">&bull;</span><span>${renderInlineMarkup(item)}</span></li>`);
31
- });
32
- inner.push(`</ul>`);
33
- }
34
- if (cell.content) {
35
- inner.push(`<div class="mt-2 space-y-2">${renderContentBlocks(cell.content)}</div>`);
36
- }
37
- parts.push(cardWrap(accent, inner.join("\n"), "flex-1"));
38
- });
39
- parts.push(`</div>`);
40
- });
41
- if (data.xAxis) {
42
- parts.push(`<div class="flex justify-between px-2 mt-1">`);
43
- parts.push(` <span class="text-xs text-d-dim font-body">${renderInlineMarkup(data.xAxis.low || "")}</span>`);
44
- if (data.xAxis.label) {
45
- parts.push(` <span class="text-xs font-bold text-d-muted font-body">${renderInlineMarkup(data.xAxis.label)}</span>`);
46
- }
47
- parts.push(` <span class="text-xs text-d-dim font-body">${renderInlineMarkup(data.xAxis.high || "")}</span>`);
48
- parts.push(`</div>`);
49
- }
50
- parts.push(`</div>`);
51
- parts.push(`</div>`);
52
- return parts.join("\n");
53
- };
@@ -1,2 +0,0 @@
1
- import type { SplitSlide } from "../schema.js";
2
- export declare const layoutSplit: (data: SplitSlide) => string;
@@ -1,51 +0,0 @@
1
- import { renderInlineMarkup, c, accentBar, resolveAccent } from "../utils.js";
2
- import { renderContentBlocks } from "../blocks.js";
3
- const resolveValign = (valign) => {
4
- if (valign === "top")
5
- return "justify-start";
6
- if (valign === "bottom")
7
- return "justify-end";
8
- return "justify-center";
9
- };
10
- const buildSplitPanel = (panel, fallbackAccent, ratio) => {
11
- const accent = panel.accentColor || fallbackAccent;
12
- const bg = panel.dark ? "bg-d-card" : "";
13
- const vCls = resolveValign(panel.valign);
14
- const lines = [];
15
- lines.push(`<div class="${bg} flex flex-col ${vCls} px-10 py-8" style="flex: ${ratio}">`);
16
- if (panel.label) {
17
- if (panel.labelBadge) {
18
- lines.push(` <span class="inline-block self-start px-6 py-2.5 rounded-lg bg-${c(accent)} text-lg font-bold text-white font-title mb-4">${renderInlineMarkup(panel.label)}</span>`);
19
- }
20
- else {
21
- lines.push(` <p class="text-sm font-bold text-${c(accent)} font-body mb-2">${renderInlineMarkup(panel.label)}</p>`);
22
- }
23
- }
24
- if (panel.title) {
25
- lines.push(` <h2 class="text-[36px] leading-tight font-title font-bold text-d-text">${renderInlineMarkup(panel.title)}</h2>`);
26
- }
27
- if (panel.subtitle) {
28
- lines.push(` <p class="text-base text-d-dim font-body mt-3">${renderInlineMarkup(panel.subtitle)}</p>`);
29
- }
30
- if (panel.content) {
31
- lines.push(` <div class="mt-6 space-y-3">${renderContentBlocks(panel.content)}</div>`);
32
- }
33
- lines.push(`</div>`);
34
- return lines.join("\n");
35
- };
36
- export const layoutSplit = (data) => {
37
- const accent = resolveAccent(data.accentColor);
38
- const parts = [];
39
- parts.push(accentBar(accent));
40
- const leftRatio = data.left?.ratio || 50;
41
- const rightRatio = data.right?.ratio || 50;
42
- parts.push(`<div class="flex h-full">`);
43
- if (data.left) {
44
- parts.push(buildSplitPanel(data.left, accent, leftRatio));
45
- }
46
- if (data.right) {
47
- parts.push(buildSplitPanel(data.right, accent, rightRatio));
48
- }
49
- parts.push(`</div>`);
50
- return parts.join("\n");
51
- };
@@ -1,2 +0,0 @@
1
- import type { StatsSlide } from "../schema.js";
2
- export declare const layoutStats: (data: StatsSlide) => string;
@@ -1,23 +0,0 @@
1
- import { renderInlineMarkup, c, resolveItemColor, resolveChangeColor, centeredSlideHeader, renderOptionalCallout } from "../utils.js";
2
- export const layoutStats = (data) => {
3
- const stats = data.stats || [];
4
- const parts = [];
5
- parts.push(centeredSlideHeader(data));
6
- // Stats cards
7
- parts.push(`<div class="flex gap-6 mt-10">`);
8
- stats.forEach((stat) => {
9
- const color = resolveItemColor(stat.color, data.accentColor);
10
- parts.push(`<div class="flex-1 bg-d-card rounded-lg shadow-lg p-10 text-center">`);
11
- parts.push(` <div class="h-[3px] bg-${c(color)} rounded-full w-12 mx-auto mb-6"></div>`);
12
- parts.push(` <p class="text-[52px] font-bold text-${c(color)} font-body leading-none">${renderInlineMarkup(stat.value)}</p>`);
13
- parts.push(` <p class="text-lg text-d-muted font-body mt-4">${renderInlineMarkup(stat.label)}</p>`);
14
- if (stat.change) {
15
- parts.push(` <p class="text-base font-bold text-${c(resolveChangeColor(stat.change))} font-body mt-3">${renderInlineMarkup(stat.change)}</p>`);
16
- }
17
- parts.push(`</div>`);
18
- });
19
- parts.push(`</div>`);
20
- parts.push(`</div>`);
21
- parts.push(renderOptionalCallout(data.callout));
22
- return parts.join("\n");
23
- };
@@ -1,2 +0,0 @@
1
- import type { TableSlide } from "../schema.js";
2
- export declare const layoutTable: (data: TableSlide) => string;