mulmocast 2.6.16 → 2.6.18
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/lib/actions/viewer.js +1 -1
- package/lib/cli/bin.js +0 -0
- package/lib/mcp/server.js +0 -0
- package/lib/types/schema.d.ts +4321 -479
- package/lib/types/schema.js +2 -2
- package/lib/utils/context.d.ts +1237 -689
- package/lib/utils/image_plugins/slide.d.ts +1 -1
- package/lib/utils/image_plugins/slide.js +1 -1
- package/package.json +8 -7
- package/lib/data/styles.d.ts +0 -255
- package/lib/data/styles.js +0 -284
- package/lib/slide/blocks.d.ts +0 -13
- package/lib/slide/blocks.js +0 -251
- package/lib/slide/index.d.ts +0 -6
- package/lib/slide/index.js +0 -7
- package/lib/slide/layouts/big_quote.d.ts +0 -2
- package/lib/slide/layouts/big_quote.js +0 -19
- package/lib/slide/layouts/columns.d.ts +0 -2
- package/lib/slide/layouts/columns.js +0 -53
- package/lib/slide/layouts/comparison.d.ts +0 -2
- package/lib/slide/layouts/comparison.js +0 -25
- package/lib/slide/layouts/funnel.d.ts +0 -2
- package/lib/slide/layouts/funnel.js +0 -25
- package/lib/slide/layouts/grid.d.ts +0 -2
- package/lib/slide/layouts/grid.js +0 -38
- package/lib/slide/layouts/index.d.ts +0 -3
- package/lib/slide/layouts/index.js +0 -46
- package/lib/slide/layouts/matrix.d.ts +0 -2
- package/lib/slide/layouts/matrix.js +0 -53
- package/lib/slide/layouts/split.d.ts +0 -2
- package/lib/slide/layouts/split.js +0 -51
- package/lib/slide/layouts/stats.d.ts +0 -2
- package/lib/slide/layouts/stats.js +0 -23
- package/lib/slide/layouts/table.d.ts +0 -2
- package/lib/slide/layouts/table.js +0 -10
- package/lib/slide/layouts/timeline.d.ts +0 -2
- package/lib/slide/layouts/timeline.js +0 -27
- package/lib/slide/layouts/title.d.ts +0 -2
- package/lib/slide/layouts/title.js +0 -19
- package/lib/slide/layouts/waterfall.d.ts +0 -2
- package/lib/slide/layouts/waterfall.js +0 -63
- package/lib/slide/render.d.ts +0 -17
- package/lib/slide/render.js +0 -101
- package/lib/slide/schema.d.ts +0 -9309
- package/lib/slide/schema.js +0 -434
- package/lib/slide/utils.d.ts +0 -76
- package/lib/slide/utils.js +0 -243
- package/lib/types/slide.d.ts +0 -9309
- package/lib/types/slide.js +0 -434
- package/lib/utils/browser_pool.d.ts +0 -5
- package/lib/utils/browser_pool.js +0 -39
- package/lib/utils/markdown.d.ts +0 -3
- package/lib/utils/markdown.js +0 -49
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { slideHeader, renderOptionalCallout } from "../utils.js";
|
|
2
|
-
import { renderTableCore } from "../blocks.js";
|
|
3
|
-
export const layoutTable = (data) => {
|
|
4
|
-
const parts = [slideHeader(data)];
|
|
5
|
-
parts.push(`<div class="px-12 mt-5 flex-1 overflow-auto">`);
|
|
6
|
-
parts.push(renderTableCore(data.headers, data.rows, data.rowHeaders, data.striped));
|
|
7
|
-
parts.push(`</div>`);
|
|
8
|
-
parts.push(renderOptionalCallout(data.callout));
|
|
9
|
-
return parts.join("\n");
|
|
10
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { renderInlineMarkup, c, resolveItemColor, centeredSlideHeader } from "../utils.js";
|
|
2
|
-
export const layoutTimeline = (data) => {
|
|
3
|
-
const parts = [];
|
|
4
|
-
const items = data.items || [];
|
|
5
|
-
parts.push(centeredSlideHeader(data));
|
|
6
|
-
// Timeline items
|
|
7
|
-
parts.push(`<div class="flex items-start mt-10 relative">`);
|
|
8
|
-
parts.push(`<div class="absolute left-4 right-4 top-[52px] h-[2px] bg-d-alt"></div>`);
|
|
9
|
-
items.forEach((item) => {
|
|
10
|
-
const color = resolveItemColor(item.color, data.accentColor);
|
|
11
|
-
const dotBorder = item.done ? `bg-${c(color)}` : `bg-d-alt`;
|
|
12
|
-
const dotInner = item.done ? "bg-d-text" : `bg-${c(color)}`;
|
|
13
|
-
parts.push(`<div class="flex-1 flex flex-col items-center text-center relative z-10">`);
|
|
14
|
-
parts.push(` <div class="w-10 h-10 rounded-full ${dotBorder} flex items-center justify-center shadow-lg">`);
|
|
15
|
-
parts.push(` <div class="w-4 h-4 rounded-full ${dotInner}"></div>`);
|
|
16
|
-
parts.push(` </div>`);
|
|
17
|
-
parts.push(` <p class="text-sm font-bold text-${c(color)} font-body mt-4">${renderInlineMarkup(item.date)}</p>`);
|
|
18
|
-
parts.push(` <p class="text-base font-bold text-d-text font-body mt-2">${renderInlineMarkup(item.title)}</p>`);
|
|
19
|
-
if (item.description) {
|
|
20
|
-
parts.push(` <p class="text-sm text-d-muted font-body mt-1 px-3">${renderInlineMarkup(item.description)}</p>`);
|
|
21
|
-
}
|
|
22
|
-
parts.push(`</div>`);
|
|
23
|
-
});
|
|
24
|
-
parts.push(`</div>`);
|
|
25
|
-
parts.push(`</div>`);
|
|
26
|
-
return parts.join("\n");
|
|
27
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { renderInlineMarkup, accentBar } from "../utils.js";
|
|
2
|
-
export const layoutTitle = (data) => {
|
|
3
|
-
return [
|
|
4
|
-
accentBar("primary"),
|
|
5
|
-
`<div class="absolute -top-20 -right-8 w-[360px] h-[360px] rounded-full bg-d-primary opacity-10"></div>`,
|
|
6
|
-
`<div class="absolute -bottom-12 -left-16 w-[280px] h-[280px] rounded-full bg-d-accent opacity-10"></div>`,
|
|
7
|
-
`<div class="flex flex-col justify-center h-full px-16 relative z-10">`,
|
|
8
|
-
` <h1 class="text-[60px] leading-tight font-title font-bold text-d-text">${renderInlineMarkup(data.title)}</h1>`,
|
|
9
|
-
data.subtitle ? ` <p class="text-2xl text-d-muted mt-6 font-body">${renderInlineMarkup(data.subtitle)}</p>` : "",
|
|
10
|
-
data.author ? ` <p class="text-lg text-d-dim mt-10 font-body">${renderInlineMarkup(data.author)}</p>` : "",
|
|
11
|
-
data.note
|
|
12
|
-
? ` <div class="bg-d-card px-4 py-2 mt-6 inline-block rounded"><p class="text-sm text-d-dim font-body">${renderInlineMarkup(data.note)}</p></div>`
|
|
13
|
-
: "",
|
|
14
|
-
`</div>`,
|
|
15
|
-
accentBar("accent", "absolute bottom-0 left-0 right-0"),
|
|
16
|
-
]
|
|
17
|
-
.filter(Boolean)
|
|
18
|
-
.join("\n");
|
|
19
|
-
};
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { renderInlineMarkup, c, slideHeader, renderOptionalCallout } from "../utils.js";
|
|
2
|
-
/** Height of the chart area as percentage of available space */
|
|
3
|
-
const CHART_HEIGHT_PCT = 75;
|
|
4
|
-
export const layoutWaterfall = (data) => {
|
|
5
|
-
const parts = [slideHeader(data)];
|
|
6
|
-
const items = data.items || [];
|
|
7
|
-
const positions = buildWaterfallPositions(items);
|
|
8
|
-
const globalMax = Math.max(...positions.map((p) => p.top));
|
|
9
|
-
const globalMin = Math.min(...positions.map((p) => p.bottom));
|
|
10
|
-
const range = globalMax - globalMin || 1;
|
|
11
|
-
parts.push(`<div class="flex gap-1 px-12 mt-4 flex-1" style="min-height: 0">`);
|
|
12
|
-
items.forEach((item, i) => {
|
|
13
|
-
const pos = positions[i];
|
|
14
|
-
const isTotal = item.isTotal ?? false;
|
|
15
|
-
const isPositive = item.value >= 0;
|
|
16
|
-
const color = resolveBarColor(item.color, isTotal, isPositive);
|
|
17
|
-
const bottomPct = ((pos.bottom - globalMin) / range) * CHART_HEIGHT_PCT;
|
|
18
|
-
const heightPct = Math.max(((pos.top - pos.bottom) / range) * CHART_HEIGHT_PCT, 1.5);
|
|
19
|
-
const topOfBar = bottomPct + heightPct;
|
|
20
|
-
const labelTopPct = 100 - topOfBar;
|
|
21
|
-
const formattedValue = formatValue(item.value, data.unit, isTotal);
|
|
22
|
-
parts.push(`<div class="flex-1 relative" style="height: 100%">`);
|
|
23
|
-
// Value label (above bar)
|
|
24
|
-
parts.push(` <p class="absolute w-full text-xs font-bold text-d-text font-body text-center" style="top: ${labelTopPct - 4}%">${renderInlineMarkup(formattedValue)}</p>`);
|
|
25
|
-
// Bar (absolute positioned from bottom)
|
|
26
|
-
parts.push(` <div class="absolute left-1 right-1 bg-${c(color)} rounded-t" style="bottom: ${bottomPct}%; height: ${heightPct}%"></div>`);
|
|
27
|
-
// Bottom label
|
|
28
|
-
parts.push(` <p class="absolute bottom-0 w-full text-xs text-d-muted font-body text-center" style="transform: translateY(100%)">${renderInlineMarkup(item.label)}</p>`);
|
|
29
|
-
parts.push(`</div>`);
|
|
30
|
-
});
|
|
31
|
-
parts.push(`</div>`);
|
|
32
|
-
// Labels area
|
|
33
|
-
parts.push(`<div class="h-10 shrink-0"></div>`);
|
|
34
|
-
parts.push(renderOptionalCallout(data.callout));
|
|
35
|
-
return parts.join("\n");
|
|
36
|
-
};
|
|
37
|
-
const buildWaterfallPositions = (items) => {
|
|
38
|
-
let runningTotal = 0;
|
|
39
|
-
return items.map((item) => {
|
|
40
|
-
if (item.isTotal) {
|
|
41
|
-
runningTotal = item.value;
|
|
42
|
-
return { top: Math.max(item.value, 0), bottom: Math.min(item.value, 0) };
|
|
43
|
-
}
|
|
44
|
-
const prevTotal = runningTotal;
|
|
45
|
-
runningTotal += item.value;
|
|
46
|
-
if (item.value >= 0) {
|
|
47
|
-
return { top: runningTotal, bottom: prevTotal };
|
|
48
|
-
}
|
|
49
|
-
return { top: prevTotal, bottom: runningTotal };
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
|
-
const resolveBarColor = (itemColor, isTotal, isPositive) => {
|
|
53
|
-
if (itemColor)
|
|
54
|
-
return itemColor;
|
|
55
|
-
if (isTotal)
|
|
56
|
-
return "primary";
|
|
57
|
-
return isPositive ? "success" : "danger";
|
|
58
|
-
};
|
|
59
|
-
const formatValue = (value, unit, isTotal) => {
|
|
60
|
-
const prefix = !isTotal && value > 0 ? "+" : "";
|
|
61
|
-
const suffix = unit ? ` ${unit}` : "";
|
|
62
|
-
return `${prefix}${value}${suffix}`;
|
|
63
|
-
};
|
package/lib/slide/render.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { SlideTheme, SlideLayout } from "./schema.js";
|
|
2
|
-
/** Pre-resolved branding data (all sources converted to data URLs) */
|
|
3
|
-
export type ResolvedBranding = {
|
|
4
|
-
logo?: {
|
|
5
|
-
dataUrl: string;
|
|
6
|
-
position: string;
|
|
7
|
-
width: number;
|
|
8
|
-
};
|
|
9
|
-
backgroundImage?: {
|
|
10
|
-
dataUrl: string;
|
|
11
|
-
size: string;
|
|
12
|
-
opacity: number;
|
|
13
|
-
bgOpacity?: number;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
/** Generate a complete HTML document for a single slide */
|
|
17
|
-
export declare const generateSlideHTML: (theme: SlideTheme, slide: SlideLayout, reference?: string, branding?: ResolvedBranding) => string;
|
package/lib/slide/render.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { escapeHtml, buildTailwindConfig, sanitizeHex, detectBlockTypes } from "./utils.js";
|
|
2
|
-
import { renderSlideContent } from "./layouts/index.js";
|
|
3
|
-
/** Determine if a hex color is dark (luminance < 128) */
|
|
4
|
-
const isDarkBg = (hex) => {
|
|
5
|
-
const r = parseInt(hex.slice(0, 2), 16);
|
|
6
|
-
const g = parseInt(hex.slice(2, 4), 16);
|
|
7
|
-
const b = parseInt(hex.slice(4, 6), 16);
|
|
8
|
-
return (r * 299 + g * 587 + b * 114) / 1000 < 128;
|
|
9
|
-
};
|
|
10
|
-
/** Build CDN script tags for chart/mermaid when needed */
|
|
11
|
-
const buildCdnScripts = (theme, slide) => {
|
|
12
|
-
const { hasChart, hasMermaid, chartPlugins } = detectBlockTypes(slide);
|
|
13
|
-
const scripts = [];
|
|
14
|
-
if (hasChart) {
|
|
15
|
-
scripts.push('<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>');
|
|
16
|
-
chartPlugins.forEach((cdn) => {
|
|
17
|
-
scripts.push(`<script src="${cdn}"></script>`);
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
if (hasMermaid) {
|
|
21
|
-
const mermaidTheme = isDarkBg(theme.colors.bg) ? "dark" : "default";
|
|
22
|
-
scripts.push(`<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
|
23
|
-
<script>mermaid.initialize({startOnLoad:true,theme:'${mermaidTheme}'})</script>`);
|
|
24
|
-
}
|
|
25
|
-
return scripts.join("\n");
|
|
26
|
-
};
|
|
27
|
-
/** Map branding logo position to Tailwind CSS classes */
|
|
28
|
-
const logoPositionClasses = {
|
|
29
|
-
"top-left": "top-5 left-6",
|
|
30
|
-
"top-right": "top-5 right-6",
|
|
31
|
-
"bottom-left": "bottom-5 left-6",
|
|
32
|
-
"bottom-right": "bottom-5 right-6",
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* Render branding background layers.
|
|
36
|
-
* - Without bgOpacity: image overlaid on slide bg at given opacity
|
|
37
|
-
* - With bgOpacity: image at full opacity, then slide bg color as semi-transparent overlay
|
|
38
|
-
*/
|
|
39
|
-
const renderBrandingBackground = (branding, bgHex) => {
|
|
40
|
-
if (!branding.backgroundImage)
|
|
41
|
-
return "";
|
|
42
|
-
const { dataUrl, size, opacity, bgOpacity } = branding.backgroundImage;
|
|
43
|
-
const bgSize = size === "fill" ? "100% 100%" : size;
|
|
44
|
-
if (bgOpacity !== undefined) {
|
|
45
|
-
const parts = [];
|
|
46
|
-
parts.push(`<div class="absolute inset-0 z-0" style="background-image:url('${dataUrl}');background-size:${bgSize};background-position:center;background-repeat:no-repeat;opacity:${opacity}"></div>`);
|
|
47
|
-
parts.push(`<div class="absolute inset-0 z-0" style="background-color:#${bgHex};opacity:${bgOpacity}"></div>`);
|
|
48
|
-
return parts.join("\n");
|
|
49
|
-
}
|
|
50
|
-
return `<div class="absolute inset-0 z-0" style="background-image:url('${dataUrl}');background-size:${bgSize};background-position:center;background-repeat:no-repeat;opacity:${opacity}"></div>`;
|
|
51
|
-
};
|
|
52
|
-
/** Render branding logo element */
|
|
53
|
-
const renderBrandingLogo = (branding) => {
|
|
54
|
-
if (!branding.logo)
|
|
55
|
-
return "";
|
|
56
|
-
const { dataUrl, position, width } = branding.logo;
|
|
57
|
-
const posClasses = logoPositionClasses[position] ?? logoPositionClasses["top-right"];
|
|
58
|
-
return `<img class="absolute ${posClasses} z-10" src="${dataUrl}" width="${width}" alt="" style="pointer-events:none">`;
|
|
59
|
-
};
|
|
60
|
-
/** Generate a complete HTML document for a single slide */
|
|
61
|
-
export const generateSlideHTML = (theme, slide, reference, branding) => {
|
|
62
|
-
const content = renderSlideContent(slide);
|
|
63
|
-
const twConfig = buildTailwindConfig(theme);
|
|
64
|
-
const cdnScripts = buildCdnScripts(theme, slide);
|
|
65
|
-
const slideStyle = slide.style;
|
|
66
|
-
const hasBgOpacity = branding?.backgroundImage?.bgOpacity !== undefined;
|
|
67
|
-
const bgCls = hasBgOpacity || slideStyle?.bgColor ? "" : "bg-d-bg";
|
|
68
|
-
const bgColorStyle = slideStyle?.bgColor ? ` style="background-color:#${sanitizeHex(slideStyle.bgColor)}"` : "";
|
|
69
|
-
const inlineStyle = hasBgOpacity ? "" : bgColorStyle;
|
|
70
|
-
const footer = slideStyle?.footer ? `<p class="absolute bottom-2 right-4 text-xs text-d-dim font-body">${escapeHtml(slideStyle.footer)}</p>` : "";
|
|
71
|
-
const referenceHtml = reference
|
|
72
|
-
? `<div class="mt-auto px-4 pb-2"><p class="text-sm text-d-muted font-body opacity-80">${escapeHtml(reference)}</p></div>`
|
|
73
|
-
: "";
|
|
74
|
-
const bgHex = sanitizeHex(slideStyle?.bgColor ?? theme.colors.bg);
|
|
75
|
-
const brandingBg = branding ? renderBrandingBackground(branding, bgHex) : "";
|
|
76
|
-
const brandingLogo = branding ? renderBrandingLogo(branding) : "";
|
|
77
|
-
return `<!DOCTYPE html>
|
|
78
|
-
<html lang="en" class="h-full">
|
|
79
|
-
<head>
|
|
80
|
-
<meta charset="UTF-8">
|
|
81
|
-
<meta name="viewport" content="width=1280">
|
|
82
|
-
<script src="https://cdn.tailwindcss.com"></script>
|
|
83
|
-
<script>tailwind.config = ${twConfig}</script>
|
|
84
|
-
${cdnScripts}
|
|
85
|
-
<style>
|
|
86
|
-
html, body { height: 100%; margin: 0; padding: 0; overflow: hidden; }
|
|
87
|
-
</style>
|
|
88
|
-
</head>
|
|
89
|
-
<body class="h-full">
|
|
90
|
-
<div class="relative overflow-hidden ${bgCls} w-full h-full flex flex-col"${inlineStyle}>
|
|
91
|
-
${brandingBg}
|
|
92
|
-
<div class="relative z-[1] flex flex-col flex-1">
|
|
93
|
-
${content}
|
|
94
|
-
${referenceHtml}
|
|
95
|
-
${footer}
|
|
96
|
-
</div>
|
|
97
|
-
${brandingLogo}
|
|
98
|
-
</div>
|
|
99
|
-
</body>
|
|
100
|
-
</html>`;
|
|
101
|
-
};
|