mulmocast 2.9.2 → 2.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/lib/actions/image_agents.js +2 -2
- package/lib/cli/bin.js +0 -0
- package/lib/index.browser.d.ts +7 -0
- package/lib/index.browser.js +6 -0
- package/lib/methods/mulmo_beat_node.d.ts +3 -3
- package/lib/types/const.d.ts +7 -0
- package/lib/types/const.js +7 -0
- package/lib/types/schema.js +6 -2
- package/lib/types/type.d.ts +8 -0
- package/lib/utils/beat_html/chart.d.ts +15 -0
- package/lib/utils/beat_html/chart.js +21 -0
- package/lib/utils/beat_html/html_tailwind.d.ts +19 -0
- package/lib/utils/beat_html/html_tailwind.js +20 -0
- package/lib/utils/beat_html/index.d.ts +33 -0
- package/lib/utils/beat_html/index.js +65 -0
- package/lib/utils/beat_html/markdown.d.ts +20 -0
- package/lib/utils/beat_html/markdown.js +25 -0
- package/lib/utils/beat_html/media.d.ts +14 -0
- package/lib/utils/beat_html/media.js +19 -0
- package/lib/utils/beat_html/mermaid.d.ts +14 -0
- package/lib/utils/beat_html/mermaid.js +22 -0
- package/lib/utils/beat_html/slide.d.ts +21 -0
- package/lib/utils/beat_html/slide.js +33 -0
- package/lib/utils/beat_html/text_slide.d.ts +17 -0
- package/lib/utils/beat_html/text_slide.js +24 -0
- package/lib/utils/beat_html/type.d.ts +73 -0
- package/lib/utils/context.d.ts +24 -0
- package/lib/utils/context.js +1 -1
- package/lib/utils/element_id.d.ts +26 -0
- package/lib/utils/element_id.js +31 -0
- package/lib/utils/html_escape.d.ts +14 -0
- package/lib/utils/html_escape.js +30 -0
- package/lib/utils/image_plugins/beat.d.ts +2 -2
- package/lib/utils/image_plugins/bg_image_util.d.ts +4 -1
- package/lib/utils/image_plugins/bg_image_util.js +2 -1
- package/lib/utils/image_plugins/chart.d.ts +3 -3
- package/lib/utils/image_plugins/chart.js +6 -30
- package/lib/utils/image_plugins/chart_html.d.ts +24 -0
- package/lib/utils/image_plugins/chart_html.js +81 -0
- package/lib/utils/image_plugins/html_tailwind.d.ts +3 -3
- package/lib/utils/image_plugins/html_tailwind.js +2 -5
- package/lib/utils/image_plugins/html_tailwind_markup.d.ts +21 -0
- package/lib/utils/image_plugins/html_tailwind_markup.js +8 -0
- package/lib/utils/image_plugins/image.d.ts +1 -1
- package/lib/utils/image_plugins/index.d.ts +7 -7
- package/lib/utils/image_plugins/markdown.d.ts +4 -4
- package/lib/utils/image_plugins/markdown.js +41 -30
- package/lib/utils/image_plugins/markdown_layout.d.ts +46 -4
- package/lib/utils/image_plugins/markdown_layout.js +96 -83
- package/lib/utils/image_plugins/media_html.d.ts +16 -0
- package/lib/utils/image_plugins/media_html.js +39 -0
- package/lib/utils/image_plugins/mermaid.d.ts +5 -4
- package/lib/utils/image_plugins/mermaid.js +4 -16
- package/lib/utils/image_plugins/mermaid_html.d.ts +22 -0
- package/lib/utils/image_plugins/mermaid_html.js +36 -0
- package/lib/utils/image_plugins/movie.d.ts +4 -4
- package/lib/utils/image_plugins/movie.js +2 -15
- package/lib/utils/image_plugins/slide.d.ts +3 -3
- package/lib/utils/image_plugins/source.d.ts +2 -2
- package/lib/utils/image_plugins/text_slide.d.ts +4 -4
- package/lib/utils/image_plugins/utils.d.ts +2 -2
- package/lib/utils/image_plugins/vision.d.ts +3 -3
- package/lib/utils/image_plugins/voice_over.d.ts +2 -2
- package/lib/utils/swipe_to_html.d.ts +18 -0
- package/lib/utils/swipe_to_html.js +26 -2
- package/package.json +15 -13
- package/scripts/test/test_captions_2.json~ +278 -0
- package/scripts/test/test_en_portrait.json~ +31 -0
- package/scripts/test/test_slide_image_ref_gemini_en.json~ +289 -0
- package/scripts/test/test_vertexai.json~ +21 -0
- package/lib/agents/image_google_agent.d.ts +0 -5
- package/lib/agents/image_google_agent.js +0 -86
- package/lib/agents/movie_google_agent.d.ts +0 -9
- package/lib/agents/movie_google_agent.js +0 -122
- package/lib/agents/mulmo_prompts_agent.d.ts +0 -7
- package/lib/agents/mulmo_prompts_agent.js +0 -37
- package/lib/agents/prompts_data.d.ts +0 -15
- package/lib/agents/prompts_data.js +0 -16
- package/lib/agents/tts_nijivoice_agent.d.ts +0 -5
- package/lib/agents/tts_nijivoice_agent.js +0 -69
- package/lib/agents/validate_mulmo_script_agent.d.ts +0 -17
- package/lib/agents/validate_mulmo_script_agent.js +0 -34
- package/lib/cli/args.d.ts +0 -15
- package/lib/cli/args.js +0 -62
- package/lib/cli/cli.d.ts +0 -17
- package/lib/cli/cli.js +0 -117
- package/lib/cli/run.d.ts +0 -2
- package/lib/cli/run.js +0 -3
- package/lib/cli/tool-args.d.ts +0 -16
- package/lib/cli/tool-args.js +0 -64
- package/lib/cli/tool-cli.d.ts +0 -2
- package/lib/cli/tool-cli.js +0 -32
- package/lib/cli/tool_commands/prompt/builder.d.ts +0 -4
- package/lib/cli/tool_commands/prompt/builder.js +0 -11
- package/lib/cli/tool_commands/prompt/handler.d.ts +0 -4
- package/lib/cli/tool_commands/prompt/handler.js +0 -14
- package/lib/cli/tool_commands/prompt/index.d.ts +0 -4
- package/lib/cli/tool_commands/prompt/index.js +0 -4
- package/lib/cli/tool_commands/schema/builder.d.ts +0 -2
- package/lib/cli/tool_commands/schema/builder.js +0 -3
- package/lib/cli/tool_commands/schema/handler.d.ts +0 -2
- package/lib/cli/tool_commands/schema/handler.js +0 -12
- package/lib/cli/tool_commands/schema/index.d.ts +0 -4
- package/lib/cli/tool_commands/schema/index.js +0 -4
- package/lib/cli/tool_commands/scripting/builder.d.ts +0 -20
- package/lib/cli/tool_commands/scripting/builder.js +0 -63
- package/lib/cli/tool_commands/scripting/handler.d.ts +0 -12
- package/lib/cli/tool_commands/scripting/handler.js +0 -36
- package/lib/cli/tool_commands/scripting/index.d.ts +0 -4
- package/lib/cli/tool_commands/scripting/index.js +0 -4
- package/lib/index.d.ts +0 -8
- package/lib/index.js +0 -8
- package/lib/methods/mulmo_script_template.d.ts +0 -4
- package/lib/methods/mulmo_script_template.js +0 -6
- package/lib/methods/mulmo_studio.d.ts +0 -8
- package/lib/methods/mulmo_studio.js +0 -25
- 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/tools/prompt.js +0 -18
- package/lib/tools/seed.d.ts +0 -3
- package/lib/tools/seed.js +0 -211
- package/lib/tools/seed_from_url.d.ts +0 -3
- package/lib/tools/seed_from_url.js +0 -188
- package/lib/types/slide.d.ts +0 -9309
- package/lib/types/slide.js +0 -434
- package/lib/utils/assets.d.ts +0 -18
- package/lib/utils/assets.js +0 -101
- package/lib/utils/cli.d.ts +0 -1
- package/lib/utils/cli.js +0 -15
- package/lib/utils/const.d.ts +0 -12
- package/lib/utils/const.js +0 -12
- package/lib/utils/image_preprocess.d.ts +0 -14
- package/lib/utils/image_preprocess.js +0 -52
- package/lib/utils/markdown.d.ts +0 -3
- package/lib/utils/markdown.js +0 -42
- package/lib/utils/pdf.d.ts +0 -9
- package/lib/utils/pdf.js +0 -77
- package/lib/utils/preprocess.d.ts +0 -343
- package/lib/utils/preprocess.js +0 -58
- package/lib/utils/provider2agent.d.ts +0 -141
- package/lib/utils/provider2agent.js +0 -267
- package/lib/utils/text_hash.d.ts +0 -1
- package/lib/utils/text_hash.js +0 -4
- /package/lib/{tools/prompt.d.ts → utils/beat_html/type.js} +0 -0
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Argv } from "yargs";
|
|
2
|
-
export declare const builder: (yargs: Argv) => Argv<{
|
|
3
|
-
o: string | undefined;
|
|
4
|
-
} & {
|
|
5
|
-
b: string | undefined;
|
|
6
|
-
} & {
|
|
7
|
-
u: string[] | never[];
|
|
8
|
-
} & {
|
|
9
|
-
i: boolean | undefined;
|
|
10
|
-
} & {
|
|
11
|
-
t: string | undefined;
|
|
12
|
-
} & {
|
|
13
|
-
c: string | undefined;
|
|
14
|
-
} & {
|
|
15
|
-
s: string;
|
|
16
|
-
} & {
|
|
17
|
-
llm_agent: string | undefined;
|
|
18
|
-
} & {
|
|
19
|
-
llm_model: string | undefined;
|
|
20
|
-
}>;
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { llmAgents } from "../../../utils/utils.js";
|
|
2
|
-
import { getAvailableTemplates } from "../../../utils/file.js";
|
|
3
|
-
const availableTemplateNames = getAvailableTemplates().map((template) => template.filename);
|
|
4
|
-
export const builder = (yargs) => {
|
|
5
|
-
return yargs
|
|
6
|
-
.option("o", {
|
|
7
|
-
alias: "outdir",
|
|
8
|
-
description: "output dir",
|
|
9
|
-
demandOption: false,
|
|
10
|
-
type: "string",
|
|
11
|
-
})
|
|
12
|
-
.option("b", {
|
|
13
|
-
alias: "basedir",
|
|
14
|
-
description: "base dir",
|
|
15
|
-
demandOption: false,
|
|
16
|
-
type: "string",
|
|
17
|
-
})
|
|
18
|
-
.option("u", {
|
|
19
|
-
alias: "url",
|
|
20
|
-
description: "URLs to reference (required when not in interactive mode)",
|
|
21
|
-
demandOption: false,
|
|
22
|
-
default: [],
|
|
23
|
-
type: "array",
|
|
24
|
-
string: true,
|
|
25
|
-
})
|
|
26
|
-
.option("i", {
|
|
27
|
-
alias: "interactive",
|
|
28
|
-
description: "Generate script in interactive mode with user prompts",
|
|
29
|
-
demandOption: false,
|
|
30
|
-
type: "boolean",
|
|
31
|
-
})
|
|
32
|
-
.option("t", {
|
|
33
|
-
alias: "template",
|
|
34
|
-
description: "Template name to use",
|
|
35
|
-
demandOption: false,
|
|
36
|
-
choices: availableTemplateNames,
|
|
37
|
-
type: "string",
|
|
38
|
-
})
|
|
39
|
-
.option("c", {
|
|
40
|
-
alias: "cache",
|
|
41
|
-
description: "cache dir",
|
|
42
|
-
demandOption: false,
|
|
43
|
-
type: "string",
|
|
44
|
-
})
|
|
45
|
-
.option("s", {
|
|
46
|
-
alias: "script",
|
|
47
|
-
description: "script filename",
|
|
48
|
-
demandOption: false,
|
|
49
|
-
default: "script",
|
|
50
|
-
type: "string",
|
|
51
|
-
})
|
|
52
|
-
.option("llm_agent", {
|
|
53
|
-
description: "llm agent",
|
|
54
|
-
demandOption: false,
|
|
55
|
-
choices: llmAgents,
|
|
56
|
-
type: "string",
|
|
57
|
-
})
|
|
58
|
-
.option("llm_model", {
|
|
59
|
-
description: "llm model",
|
|
60
|
-
demandOption: false,
|
|
61
|
-
type: "string",
|
|
62
|
-
});
|
|
63
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { ToolCliArgs } from "@/src/types/cli_types.js";
|
|
2
|
-
export declare const handler: (argv: ToolCliArgs<{
|
|
3
|
-
o?: string;
|
|
4
|
-
b?: string;
|
|
5
|
-
u?: string[];
|
|
6
|
-
i?: boolean;
|
|
7
|
-
t?: string;
|
|
8
|
-
c?: string;
|
|
9
|
-
s?: string;
|
|
10
|
-
llm_agent?: string;
|
|
11
|
-
llm_model?: string;
|
|
12
|
-
}>) => Promise<void>;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { getBaseDirPath, getFullPath } from "@/src/utils/file.js";
|
|
2
|
-
import { outDirName, cacheDirName } from "../../../utils/const.js";
|
|
3
|
-
import { getUrlsIfNeeded, selectTemplate } from "@/src/utils/inquirer.js";
|
|
4
|
-
import { createMulmoScriptFromUrl } from "../../../tools/create_mulmo_script_from_url.js";
|
|
5
|
-
import { createMulmoScriptInteractively } from "../../../tools/create_mulmo_script_interactively.js";
|
|
6
|
-
import { setGraphAILogger } from "@/src/utils/cli.js";
|
|
7
|
-
export const handler = async (argv) => {
|
|
8
|
-
const { o: outdir, b: basedir, v: verbose, i: interactive, c: cache, s: filename, llm_agent, llm_model } = argv;
|
|
9
|
-
let { t: template } = argv;
|
|
10
|
-
const urls = argv.u || [];
|
|
11
|
-
const baseDirPath = getBaseDirPath(basedir);
|
|
12
|
-
const outDirPath = getFullPath(baseDirPath, outdir ?? outDirName);
|
|
13
|
-
const cacheDirPath = getFullPath(outDirPath, cache ?? cacheDirName);
|
|
14
|
-
if (!template) {
|
|
15
|
-
template = await selectTemplate();
|
|
16
|
-
}
|
|
17
|
-
setGraphAILogger(verbose, {
|
|
18
|
-
baseDirPath,
|
|
19
|
-
outDirPath,
|
|
20
|
-
cacheDirPath,
|
|
21
|
-
template,
|
|
22
|
-
urls,
|
|
23
|
-
interactive,
|
|
24
|
-
filename,
|
|
25
|
-
llm_agent,
|
|
26
|
-
llm_model,
|
|
27
|
-
});
|
|
28
|
-
const context = { outDirPath, templateName: template, urls, filename: filename, cacheDirPath, llm_model, llm_agent };
|
|
29
|
-
if (interactive) {
|
|
30
|
-
await createMulmoScriptInteractively(context);
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
context.urls = await getUrlsIfNeeded(urls);
|
|
34
|
-
await createMulmoScriptFromUrl(context);
|
|
35
|
-
}
|
|
36
|
-
};
|
package/lib/index.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export * from "./actions/index.js";
|
|
2
|
-
export * from "./cli/helpers.js";
|
|
3
|
-
export * from "./utils/file.js";
|
|
4
|
-
export * from "./utils/ffmpeg_utils.js";
|
|
5
|
-
export * from "./utils/provider2agent.js";
|
|
6
|
-
export * from "./methods/index.js";
|
|
7
|
-
export * from "./agents/index.js";
|
|
8
|
-
export * from "./types/index.js";
|
package/lib/index.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export * from "./actions/index.js";
|
|
2
|
-
export * from "./cli/helpers.js";
|
|
3
|
-
export * from "./utils/file.js";
|
|
4
|
-
export * from "./utils/ffmpeg_utils.js";
|
|
5
|
-
export * from "./utils/provider2agent.js";
|
|
6
|
-
export * from "./methods/index.js";
|
|
7
|
-
export * from "./agents/index.js";
|
|
8
|
-
export * from "./types/index.js";
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { MulmoStudio } from "../types/index.js";
|
|
2
|
-
type SessionType = "audio" | "image" | "video" | "multiLingual" | "caption" | "pdf";
|
|
3
|
-
type BeatSessionType = "audio" | "image" | "multiLingual" | "caption" | "movie";
|
|
4
|
-
export declare const MulmoStudioMethods: {
|
|
5
|
-
setSessionState(studio: MulmoStudio, sessionType: SessionType, value: boolean): void;
|
|
6
|
-
setBeatSessionState(studio: MulmoStudio, sessionType: BeatSessionType, index: number, value: boolean): void;
|
|
7
|
-
};
|
|
8
|
-
export {};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { GraphAILogger } from "graphai";
|
|
2
|
-
const notifyStateChange = (studio, sessionType) => {
|
|
3
|
-
const prefix = studio.state.inSession[sessionType] ? "<" : " >";
|
|
4
|
-
GraphAILogger.info(`${prefix} ${sessionType}`);
|
|
5
|
-
};
|
|
6
|
-
const notifyBeatStateChange = (studio, sessionType, index) => {
|
|
7
|
-
const prefix = studio.state.inBeatSession[sessionType][index] ? "{" : " }";
|
|
8
|
-
GraphAILogger.info(`${prefix} ${sessionType} ${index}`);
|
|
9
|
-
};
|
|
10
|
-
export const MulmoStudioMethods = {
|
|
11
|
-
setSessionState(studio, sessionType, value) {
|
|
12
|
-
studio.state.inSession[sessionType] = value;
|
|
13
|
-
notifyStateChange(studio, sessionType);
|
|
14
|
-
},
|
|
15
|
-
setBeatSessionState(studio, sessionType, index, value) {
|
|
16
|
-
if (value) {
|
|
17
|
-
studio.state.inBeatSession[sessionType][index] = true;
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
// NOTE: Setting to false causes the parse error in rebuildStudio in preprocess.ts
|
|
21
|
-
delete studio.state.inBeatSession[sessionType][index];
|
|
22
|
-
}
|
|
23
|
-
notifyBeatStateChange(studio, sessionType, index);
|
|
24
|
-
},
|
|
25
|
-
};
|
package/lib/slide/blocks.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { ContentBlock, TableCellValue } from "./schema.js";
|
|
2
|
-
export declare const resolveCellColor: (cellObj: {
|
|
3
|
-
color?: string;
|
|
4
|
-
}, isRowHeader: boolean) => string;
|
|
5
|
-
export declare const renderBadge: (text: string, color: string) => string;
|
|
6
|
-
export declare const renderCellValue: (cell: TableCellValue, isRowHeader: boolean) => string;
|
|
7
|
-
export declare const renderTableCore: (headers: string[] | undefined, rows: TableCellValue[][], rowHeaders?: boolean, striped?: boolean) => string;
|
|
8
|
-
/** Render a single content block to HTML */
|
|
9
|
-
export declare const renderContentBlock: (block: ContentBlock) => string;
|
|
10
|
-
/** Render an array of content blocks to HTML */
|
|
11
|
-
export declare const renderContentBlocks: (blocks: ContentBlock[]) => string;
|
|
12
|
-
/** Render content blocks with fixed aspect-ratio container for image blocks (used in card layouts) */
|
|
13
|
-
export declare const renderCardContentBlocks: (blocks: ContentBlock[]) => string;
|
package/lib/slide/blocks.js
DELETED
|
@@ -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
|
-
};
|
package/lib/slide/index.d.ts
DELETED
|
@@ -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";
|
package/lib/slide/index.js
DELETED
|
@@ -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,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(` “${renderInlineMarkup(data.quote)}”`);
|
|
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,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,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,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
|
-
};
|