yumiamd 0.1.15 → 0.1.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.
- package/README.md +32 -9
- package/dist/bin.js +1 -1
- package/dist/{chunk-7A5BHABM.js → chunk-IAEXC5SG.js} +1047 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -1
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -16,6 +16,9 @@ You can run YumiaMD immediately without installing anything via `npx`:
|
|
|
16
16
|
# Initialize a starter presentation
|
|
17
17
|
npx yumiamd init my-deck
|
|
18
18
|
|
|
19
|
+
# Launch instant dev server with live-reload
|
|
20
|
+
npx yumiamd dev presentation.yumia.md --open
|
|
21
|
+
|
|
19
22
|
# Compile presentation directly to an editable PowerPoint (.pptx)
|
|
20
23
|
npx yumiamd build presentation.yumia.md --out presentation.pptx
|
|
21
24
|
```
|
|
@@ -64,6 +67,9 @@ yumia build presentation.yumia.md --format pdf --out dist/presentation.pdf
|
|
|
64
67
|
# Compile to standalone interactive HTML5 presentation deck (.html)
|
|
65
68
|
yumia build presentation.yumia.md --format html --out dist/presentation.html
|
|
66
69
|
|
|
70
|
+
# Deploy presentation deck (static, GitHub Pages, or Vercel)
|
|
71
|
+
yumia deploy presentation.yumia.md --provider gh-pages --out public
|
|
72
|
+
|
|
67
73
|
# Watch presentation file and recompile automatically on save
|
|
68
74
|
yumia watch presentation.yumia.md --format pdf
|
|
69
75
|
|
|
@@ -96,6 +102,9 @@ author: Biagio Scaglia
|
|
|
96
102
|
|
|
97
103
|
Deterministic compilation from Markdown directly to native PowerPoint slides.
|
|
98
104
|
|
|
105
|
+
:::badge text="v0.1.15" variant="primary" :::
|
|
106
|
+
:::badge text="Multi-Target" variant="success" :::
|
|
107
|
+
|
|
99
108
|
:::notes
|
|
100
109
|
Opening slide introducing the core architectural vision.
|
|
101
110
|
:::
|
|
@@ -128,14 +137,26 @@ Opening slide introducing the core architectural vision.
|
|
|
128
137
|
|
|
129
138
|
---
|
|
130
139
|
|
|
131
|
-
#
|
|
140
|
+
# Native Charts & Data Visuals
|
|
141
|
+
|
|
142
|
+
:::chart type="bar" title="Execution Speed" labels="Parser, Layout, PDF, PPTX" data="1200, 850, 430, 680"
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
# Roadmap Timeline
|
|
147
|
+
|
|
148
|
+
:::timeline layout="horizontal"
|
|
149
|
+
|
|
150
|
+
- [Phase 1] AST & Compiler Core
|
|
151
|
+
- [Phase 2] Multi-Format Renderers
|
|
152
|
+
- [Phase 3] Rich Directives & Charts
|
|
153
|
+
- [Phase 4] Cloud Deployments
|
|
154
|
+
:::
|
|
155
|
+
|
|
156
|
+
:::step
|
|
132
157
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
| **Output Type** | Native OpenXML Shapes & Text | Flat rasterized images / screenshots |
|
|
136
|
-
| **Full Editability** | ✅ 100% Editable in PowerPoint | ❌ Read-only image slides |
|
|
137
|
-
| **Deterministic Layout** | ✅ Pixel-exact bounding boxes | ❌ Browser rendering variance |
|
|
138
|
-
| **AI / Agent Tooling** | ✅ Machine-readable schema & CLI | ❌ Complex DOM scraping |
|
|
158
|
+
- 🚀 Seamless deployment via `yumia deploy`
|
|
159
|
+
:::
|
|
139
160
|
```
|
|
140
161
|
|
|
141
162
|
---
|
|
@@ -171,8 +192,10 @@ const schema = compiler.getSchema();
|
|
|
171
192
|
|
|
172
193
|
## ✨ Key Features
|
|
173
194
|
|
|
174
|
-
- 🎯 **Native Object Principle**: Slides compiled to PowerPoint are **NOT** rasterized screenshot images. Headings, bullet points, cards, tables, and speaker notes are generated as **100% native vector PowerPoint shapes, tables & textboxes** that you can click, re-format, and edit in Microsoft PowerPoint or Google Slides.
|
|
175
|
-
- 📊 **Native
|
|
195
|
+
- 🎯 **Native Object Principle**: Slides compiled to PowerPoint are **NOT** rasterized screenshot images. Headings, bullet points, cards, tables, charts, badges, and speaker notes are generated as **100% native vector PowerPoint shapes, tables & textboxes** that you can click, re-format, and edit in Microsoft PowerPoint or Google Slides.
|
|
196
|
+
- 📊 **Native Charts & Diagrams**: Full support for `:::chart` (bar, line, pie, doughnut) and `:::mermaid` diagrams across HTML, PDF, and PowerPoint.
|
|
197
|
+
- ⏳ **Timelines, Compare & Steps**: Rich layout directives including `:::timeline`, `:::compare`, and click-to-reveal `:::step` animations.
|
|
198
|
+
- 🚀 **One-Command Cloud Deploy**: Instantly deploy decks to GitHub Pages, Vercel, or static web servers with `yumia deploy`.
|
|
176
199
|
- 📐 **Deterministic Layout Engine**: Exact coordinate calculations for stack, columns, cards, and automatic overflow detection.
|
|
177
200
|
- 🎨 **Semantic Design Tokens**: Built-in themes with typography scales, color palettes, and contrast-safe themes.
|
|
178
201
|
- 🤖 **AI-Friendly Format**: Clean Markdown syntax designed for LLM prompts and agentic workflows, complete with `yumia schema` and `--json` CLI diagnostics.
|
package/dist/bin.js
CHANGED
|
@@ -81,6 +81,45 @@ function createTable(rows, headers) {
|
|
|
81
81
|
...headers ? { headers } : {}
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
+
function createChart(chartType, labels, series, title) {
|
|
85
|
+
return {
|
|
86
|
+
type: "chart",
|
|
87
|
+
chartType,
|
|
88
|
+
labels,
|
|
89
|
+
series,
|
|
90
|
+
...title ? { title } : {}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function createMermaid(code, chartType) {
|
|
94
|
+
return {
|
|
95
|
+
type: "mermaid",
|
|
96
|
+
code,
|
|
97
|
+
...chartType ? { chartType } : {}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function createTimeline(items, layout = "horizontal") {
|
|
101
|
+
return {
|
|
102
|
+
type: "timeline",
|
|
103
|
+
items,
|
|
104
|
+
layout
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function createCompare(left, right, leftTitle, rightTitle) {
|
|
108
|
+
return {
|
|
109
|
+
type: "compare",
|
|
110
|
+
left,
|
|
111
|
+
right,
|
|
112
|
+
...leftTitle ? { leftTitle } : {},
|
|
113
|
+
...rightTitle ? { rightTitle } : {}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function createBadge(text, variant) {
|
|
117
|
+
return {
|
|
118
|
+
type: "badge",
|
|
119
|
+
text,
|
|
120
|
+
...variant ? { variant } : {}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
84
123
|
function createGroup(elements, direction = "row", gap) {
|
|
85
124
|
return {
|
|
86
125
|
type: "group",
|
|
@@ -402,6 +441,32 @@ var DefaultYumiaParser = class {
|
|
|
402
441
|
i++;
|
|
403
442
|
continue;
|
|
404
443
|
}
|
|
444
|
+
if (directiveHeader.startsWith("badge")) {
|
|
445
|
+
const badgeArg = directiveHeader.slice(5).trim();
|
|
446
|
+
const variantMatch = badgeArg.match(/variant=['"](.*?)['"]/);
|
|
447
|
+
const textMatch = badgeArg.match(/text=['"](.*?)['"]/);
|
|
448
|
+
const variant = variantMatch ? variantMatch[1] : void 0;
|
|
449
|
+
let text = textMatch ? textMatch[1] : badgeArg.replace(/variant=['"].*?['"]/, "").trim();
|
|
450
|
+
text = text.replace(/^['"](.*)['"]$/, "$1");
|
|
451
|
+
const el = createBadge(text, variant);
|
|
452
|
+
el.loc = {
|
|
453
|
+
start: { line: currentLineNum, column: 1 },
|
|
454
|
+
end: { line: currentLineNum, column: rawLine.length + 1 }
|
|
455
|
+
};
|
|
456
|
+
elements.push(el);
|
|
457
|
+
i++;
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
if (directiveHeader.startsWith("chart") && (directiveHeader.includes("data=") || directiveHeader.includes("labels="))) {
|
|
461
|
+
const el = this.parseChartDirective(directiveHeader, []);
|
|
462
|
+
el.loc = {
|
|
463
|
+
start: { line: currentLineNum, column: 1 },
|
|
464
|
+
end: { line: currentLineNum, column: rawLine.length + 1 }
|
|
465
|
+
};
|
|
466
|
+
elements.push(el);
|
|
467
|
+
i++;
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
405
470
|
const [directiveName, ...args] = directiveHeader.split(" ");
|
|
406
471
|
const directiveArg = args.join(" ").trim();
|
|
407
472
|
const blockLines = [];
|
|
@@ -410,7 +475,9 @@ var DefaultYumiaParser = class {
|
|
|
410
475
|
let closed = false;
|
|
411
476
|
while (i < lines.length) {
|
|
412
477
|
const innerLine = lines[i]?.trim() ?? "";
|
|
413
|
-
const
|
|
478
|
+
const isInlineClosed = innerLine.startsWith(":::") && innerLine.endsWith(":::") && innerLine.length > 5;
|
|
479
|
+
const isSeparator = innerLine === ":::vs" || innerLine.startsWith(":::vs ");
|
|
480
|
+
const isSingleLine = isInlineClosed || isSeparator || innerLine.startsWith(":::metric") || innerLine.startsWith(":::layout") || innerLine.startsWith(":::badge") && (innerLine.includes("text=") || innerLine.includes("variant=")) || innerLine.startsWith(":::chart") && innerLine.includes("data=");
|
|
414
481
|
if (innerLine.startsWith(":::") && innerLine.length > 3 && !isSingleLine) {
|
|
415
482
|
nestedCount++;
|
|
416
483
|
} else if (innerLine === ":::") {
|
|
@@ -473,6 +540,41 @@ var DefaultYumiaParser = class {
|
|
|
473
540
|
end: { line: baseLine + i - 1, column: 1 }
|
|
474
541
|
};
|
|
475
542
|
elements.push(el);
|
|
543
|
+
} else if (directiveName === "mermaid") {
|
|
544
|
+
const code = blockLines.join("\n").trim();
|
|
545
|
+
const el = createMermaid(code);
|
|
546
|
+
el.loc = {
|
|
547
|
+
start: { line: directiveStartLine, column: 1 },
|
|
548
|
+
end: { line: baseLine + i - 1, column: 1 }
|
|
549
|
+
};
|
|
550
|
+
elements.push(el);
|
|
551
|
+
} else if (directiveName === "chart") {
|
|
552
|
+
const el = this.parseChartDirective(directiveArg, blockLines);
|
|
553
|
+
el.loc = {
|
|
554
|
+
start: { line: directiveStartLine, column: 1 },
|
|
555
|
+
end: { line: baseLine + i - 1, column: 1 }
|
|
556
|
+
};
|
|
557
|
+
elements.push(el);
|
|
558
|
+
} else if (directiveName === "timeline") {
|
|
559
|
+
const el = this.parseTimelineBlock(directiveArg, blockLines);
|
|
560
|
+
el.loc = {
|
|
561
|
+
start: { line: directiveStartLine, column: 1 },
|
|
562
|
+
end: { line: baseLine + i - 1, column: 1 }
|
|
563
|
+
};
|
|
564
|
+
elements.push(el);
|
|
565
|
+
} else if (directiveName === "compare") {
|
|
566
|
+
const el = this.parseCompareBlock(directiveArg, blockLines, blockBaseLine);
|
|
567
|
+
el.loc = {
|
|
568
|
+
start: { line: directiveStartLine, column: 1 },
|
|
569
|
+
end: { line: baseLine + i - 1, column: 1 }
|
|
570
|
+
};
|
|
571
|
+
elements.push(el);
|
|
572
|
+
} else if (directiveName === "step") {
|
|
573
|
+
const { elements: stepElements } = this.parseLines(blockLines, blockBaseLine);
|
|
574
|
+
for (const sEl of stepElements) {
|
|
575
|
+
sEl.step = 1;
|
|
576
|
+
elements.push(sEl);
|
|
577
|
+
}
|
|
476
578
|
}
|
|
477
579
|
continue;
|
|
478
580
|
}
|
|
@@ -595,7 +697,9 @@ var DefaultYumiaParser = class {
|
|
|
595
697
|
let nestedCount = 1;
|
|
596
698
|
while (i < lines.length) {
|
|
597
699
|
const innerLine = lines[i]?.trim() ?? "";
|
|
598
|
-
const
|
|
700
|
+
const isInlineClosed = innerLine.startsWith(":::") && innerLine.endsWith(":::") && innerLine.length > 5;
|
|
701
|
+
const isSeparator = innerLine === ":::vs" || innerLine.startsWith(":::vs ");
|
|
702
|
+
const isSingleLine = isInlineClosed || isSeparator || innerLine.startsWith(":::metric") || innerLine.startsWith(":::layout") || innerLine.startsWith(":::badge") && (innerLine.includes("text=") || innerLine.includes("variant=")) || innerLine.startsWith(":::chart") && innerLine.includes("data=");
|
|
599
703
|
if (innerLine.startsWith(":::") && innerLine.length > 3 && !isSingleLine) {
|
|
600
704
|
nestedCount++;
|
|
601
705
|
} else if (innerLine === ":::") {
|
|
@@ -621,6 +725,140 @@ var DefaultYumiaParser = class {
|
|
|
621
725
|
}
|
|
622
726
|
return columns;
|
|
623
727
|
}
|
|
728
|
+
parseChartDirective(headerArg, blockLines) {
|
|
729
|
+
const typeMatch = headerArg.match(/type=['"](.*?)['"]/);
|
|
730
|
+
const titleMatch = headerArg.match(/title=['"](.*?)['"]/);
|
|
731
|
+
const labelsMatch = headerArg.match(/labels=['"](.*?)['"]/);
|
|
732
|
+
const dataMatch = headerArg.match(/data=['"](.*?)['"]/);
|
|
733
|
+
const chartType = typeMatch ? typeMatch[1] : "bar";
|
|
734
|
+
const title = titleMatch ? titleMatch[1] : void 0;
|
|
735
|
+
let labels = [];
|
|
736
|
+
const series = [];
|
|
737
|
+
if (labelsMatch && labelsMatch[1]) {
|
|
738
|
+
labels = labelsMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
739
|
+
}
|
|
740
|
+
if (dataMatch && dataMatch[1]) {
|
|
741
|
+
const rawData = dataMatch[1].trim();
|
|
742
|
+
if (rawData.includes(":")) {
|
|
743
|
+
const parts = rawData.split(",").map((p) => p.trim());
|
|
744
|
+
const values = [];
|
|
745
|
+
const extractedLabels = [];
|
|
746
|
+
for (const part of parts) {
|
|
747
|
+
const [k, v] = part.split(":").map((s) => s.trim());
|
|
748
|
+
if (k && v !== void 0) {
|
|
749
|
+
extractedLabels.push(k);
|
|
750
|
+
values.push(parseFloat(v) || 0);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
if (labels.length === 0)
|
|
754
|
+
labels = extractedLabels;
|
|
755
|
+
series.push({ name: title || "Data", values });
|
|
756
|
+
} else {
|
|
757
|
+
const values = rawData.split(",").map((v) => parseFloat(v.trim()) || 0);
|
|
758
|
+
series.push({ name: title || "Data", values });
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
for (const line of blockLines) {
|
|
762
|
+
const trimmed = line.trim();
|
|
763
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
764
|
+
continue;
|
|
765
|
+
if (trimmed.toLowerCase().startsWith("labels:")) {
|
|
766
|
+
labels = trimmed.slice(7).split(",").map((s) => s.trim()).filter(Boolean);
|
|
767
|
+
} else if (trimmed.toLowerCase().startsWith("series:")) {
|
|
768
|
+
const seriesContent = trimmed.slice(7).trim();
|
|
769
|
+
const sMatch = seriesContent.match(/^(.*?)\s*\[(.*?)\]$/);
|
|
770
|
+
if (sMatch && sMatch[1] && sMatch[2]) {
|
|
771
|
+
const sName = sMatch[1].trim();
|
|
772
|
+
const sValues = sMatch[2].split(",").map((v) => parseFloat(v.trim()) || 0);
|
|
773
|
+
series.push({ name: sName, values: sValues });
|
|
774
|
+
}
|
|
775
|
+
} else if (trimmed.includes("|")) {
|
|
776
|
+
const parts = trimmed.split("|").map((s) => s.trim());
|
|
777
|
+
if (parts.length >= 2) {
|
|
778
|
+
const [l, valStr] = parts;
|
|
779
|
+
if (l && valStr) {
|
|
780
|
+
labels.push(l);
|
|
781
|
+
const val = parseFloat(valStr) || 0;
|
|
782
|
+
if (series.length === 0)
|
|
783
|
+
series.push({ name: "Data", values: [] });
|
|
784
|
+
series[0]?.values.push(val);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
if (labels.length === 0) {
|
|
790
|
+
const maxLen = Math.max(0, ...series.map((s) => s.values.length));
|
|
791
|
+
labels = Array.from({ length: maxLen }, (_, i) => `Item ${i + 1}`);
|
|
792
|
+
}
|
|
793
|
+
return createChart(chartType, labels, series, title);
|
|
794
|
+
}
|
|
795
|
+
parseTimelineBlock(headerArg, blockLines) {
|
|
796
|
+
const layoutMatch = headerArg.match(/layout=['"](.*?)['"]/);
|
|
797
|
+
const layout = layoutMatch && layoutMatch[1] === "vertical" ? "vertical" : "horizontal";
|
|
798
|
+
const items = [];
|
|
799
|
+
for (const line of blockLines) {
|
|
800
|
+
const trimmed = line.trim();
|
|
801
|
+
if (!trimmed)
|
|
802
|
+
continue;
|
|
803
|
+
const bracketMatch = trimmed.match(/^[-*]?\s*\[(.*?)\]\s*(.*?)(?::\s*(.*))?$/);
|
|
804
|
+
if (bracketMatch && bracketMatch[1] && bracketMatch[2]) {
|
|
805
|
+
items.push({
|
|
806
|
+
date: bracketMatch[1].trim(),
|
|
807
|
+
title: bracketMatch[2].trim(),
|
|
808
|
+
description: bracketMatch[3] ? bracketMatch[3].trim() : void 0
|
|
809
|
+
});
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
if (trimmed.includes("|")) {
|
|
813
|
+
const parts = trimmed.split("|").map((s) => s.trim());
|
|
814
|
+
if (parts.length >= 2) {
|
|
815
|
+
items.push({
|
|
816
|
+
date: parts[0],
|
|
817
|
+
title: parts[1] || "",
|
|
818
|
+
description: parts[2] || void 0
|
|
819
|
+
});
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
items.push({
|
|
824
|
+
title: trimmed.replace(/^[-*]\s*/, "")
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
return createTimeline(items, layout);
|
|
828
|
+
}
|
|
829
|
+
parseCompareBlock(headerArg, blockLines, baseLine) {
|
|
830
|
+
const leftMatch = headerArg.match(/left=['"](.*?)['"]/);
|
|
831
|
+
const rightMatch = headerArg.match(/right=['"](.*?)['"]/);
|
|
832
|
+
const leftTitle = leftMatch ? leftMatch[1] : void 0;
|
|
833
|
+
const rightTitle = rightMatch ? rightMatch[1] : void 0;
|
|
834
|
+
let leftLines = [];
|
|
835
|
+
let rightLines = [];
|
|
836
|
+
let currentSide = "left";
|
|
837
|
+
for (const line of blockLines) {
|
|
838
|
+
const trimmed = line.trim();
|
|
839
|
+
if (trimmed === ":::vs" || trimmed === ":::right" || trimmed === "---") {
|
|
840
|
+
currentSide = "right";
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
if (trimmed === ":::left") {
|
|
844
|
+
currentSide = "left";
|
|
845
|
+
continue;
|
|
846
|
+
}
|
|
847
|
+
if (currentSide === "left") {
|
|
848
|
+
leftLines.push(line);
|
|
849
|
+
} else {
|
|
850
|
+
rightLines.push(line);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
if (rightLines.length === 0 && leftLines.length > 1) {
|
|
854
|
+
const half = Math.ceil(leftLines.length / 2);
|
|
855
|
+
rightLines = leftLines.slice(half);
|
|
856
|
+
leftLines = leftLines.slice(0, half);
|
|
857
|
+
}
|
|
858
|
+
const { elements: leftElements } = this.parseLines(leftLines, baseLine);
|
|
859
|
+
const { elements: rightElements } = this.parseLines(rightLines, baseLine + leftLines.length);
|
|
860
|
+
return createCompare(leftElements, rightElements, leftTitle, rightTitle);
|
|
861
|
+
}
|
|
624
862
|
};
|
|
625
863
|
function parseYumia(source, options) {
|
|
626
864
|
const parser = new DefaultYumiaParser();
|
|
@@ -2050,6 +2288,21 @@ var PptxRenderer = class {
|
|
|
2050
2288
|
case "columns":
|
|
2051
2289
|
this.renderColumns(pptxSlide, pptx, node, scaleX, scaleY, theme);
|
|
2052
2290
|
break;
|
|
2291
|
+
case "badge":
|
|
2292
|
+
this.renderBadge(pptxSlide, pptx, element, rect, theme);
|
|
2293
|
+
break;
|
|
2294
|
+
case "chart":
|
|
2295
|
+
this.renderChart(pptxSlide, pptx, element, rect, theme);
|
|
2296
|
+
break;
|
|
2297
|
+
case "timeline":
|
|
2298
|
+
this.renderTimeline(pptxSlide, pptx, element, rect, theme);
|
|
2299
|
+
break;
|
|
2300
|
+
case "compare":
|
|
2301
|
+
this.renderCompare(pptxSlide, pptx, node, scaleX, scaleY, theme);
|
|
2302
|
+
break;
|
|
2303
|
+
case "mermaid":
|
|
2304
|
+
this.renderMermaid(pptxSlide, pptx, element, rect, theme);
|
|
2305
|
+
break;
|
|
2053
2306
|
default:
|
|
2054
2307
|
break;
|
|
2055
2308
|
}
|
|
@@ -2358,6 +2611,216 @@ var PptxRenderer = class {
|
|
|
2358
2611
|
valign: "middle"
|
|
2359
2612
|
});
|
|
2360
2613
|
}
|
|
2614
|
+
renderBadge(pptxSlide, pptx, badge, rect, theme) {
|
|
2615
|
+
const colorKey = badge.variant || "primary";
|
|
2616
|
+
const badgeColor = this.cleanHexColor(theme.colors[colorKey] || theme.colors.primary);
|
|
2617
|
+
const badgeW = Math.min(2.5, Math.max(1, badge.text.length * 0.12 + 0.4));
|
|
2618
|
+
const badgeH = Math.min(0.38, rect.h);
|
|
2619
|
+
pptxSlide.addShape(pptx.ShapeType.roundRect, {
|
|
2620
|
+
x: rect.x,
|
|
2621
|
+
y: rect.y,
|
|
2622
|
+
w: badgeW,
|
|
2623
|
+
h: badgeH,
|
|
2624
|
+
fill: { color: this.cleanHexColor(theme.colors.surface) },
|
|
2625
|
+
line: { color: badgeColor, width: 1.5 },
|
|
2626
|
+
rectRadius: 0.15
|
|
2627
|
+
});
|
|
2628
|
+
pptxSlide.addText(badge.text.toUpperCase(), {
|
|
2629
|
+
x: rect.x,
|
|
2630
|
+
y: rect.y,
|
|
2631
|
+
w: badgeW,
|
|
2632
|
+
h: badgeH,
|
|
2633
|
+
fontSize: 10,
|
|
2634
|
+
bold: true,
|
|
2635
|
+
color: badgeColor,
|
|
2636
|
+
fontFace: cleanFontFace(theme.typography.headingFont),
|
|
2637
|
+
align: "center",
|
|
2638
|
+
valign: "middle"
|
|
2639
|
+
});
|
|
2640
|
+
}
|
|
2641
|
+
renderChart(pptxSlide, pptx, chart, rect, theme) {
|
|
2642
|
+
const series = chart.series || [];
|
|
2643
|
+
const labels = chart.labels || [];
|
|
2644
|
+
const chartData = series.map((s) => ({
|
|
2645
|
+
name: s.name || "Data",
|
|
2646
|
+
labels,
|
|
2647
|
+
values: s.values
|
|
2648
|
+
}));
|
|
2649
|
+
let pptxChartType = pptx.ChartType.bar;
|
|
2650
|
+
if (chart.chartType === "line")
|
|
2651
|
+
pptxChartType = pptx.ChartType.line;
|
|
2652
|
+
if (chart.chartType === "pie")
|
|
2653
|
+
pptxChartType = pptx.ChartType.pie;
|
|
2654
|
+
if (chart.chartType === "doughnut")
|
|
2655
|
+
pptxChartType = pptx.ChartType.doughnut;
|
|
2656
|
+
const chartColors = [
|
|
2657
|
+
this.cleanHexColor(theme.colors.primary),
|
|
2658
|
+
this.cleanHexColor(theme.colors.accent),
|
|
2659
|
+
this.cleanHexColor(theme.colors.secondary),
|
|
2660
|
+
this.cleanHexColor(theme.colors.success),
|
|
2661
|
+
this.cleanHexColor(theme.colors.warning)
|
|
2662
|
+
];
|
|
2663
|
+
try {
|
|
2664
|
+
pptxSlide.addChart(pptxChartType, chartData, {
|
|
2665
|
+
x: rect.x,
|
|
2666
|
+
y: rect.y,
|
|
2667
|
+
w: rect.w,
|
|
2668
|
+
h: rect.h,
|
|
2669
|
+
showTitle: Boolean(chart.title),
|
|
2670
|
+
title: chart.title || "",
|
|
2671
|
+
titleColor: this.cleanHexColor(theme.colors.text),
|
|
2672
|
+
titleFontFace: cleanFontFace(theme.typography.headingFont),
|
|
2673
|
+
showLegend: true,
|
|
2674
|
+
legendPos: "b",
|
|
2675
|
+
legendColor: this.cleanHexColor(theme.colors.muted || theme.colors.text),
|
|
2676
|
+
chartColors
|
|
2677
|
+
});
|
|
2678
|
+
} catch {
|
|
2679
|
+
pptxSlide.addShape(pptx.ShapeType.roundRect, {
|
|
2680
|
+
x: rect.x,
|
|
2681
|
+
y: rect.y,
|
|
2682
|
+
w: rect.w,
|
|
2683
|
+
h: rect.h,
|
|
2684
|
+
fill: { color: this.cleanHexColor(theme.colors.surface) },
|
|
2685
|
+
line: { color: this.cleanHexColor(theme.colors.border), width: 1 }
|
|
2686
|
+
});
|
|
2687
|
+
pptxSlide.addText(`[Chart: ${chart.title || chart.chartType}]`, {
|
|
2688
|
+
x: rect.x,
|
|
2689
|
+
y: rect.y,
|
|
2690
|
+
w: rect.w,
|
|
2691
|
+
h: rect.h,
|
|
2692
|
+
color: this.cleanHexColor(theme.colors.primary),
|
|
2693
|
+
align: "center",
|
|
2694
|
+
valign: "middle"
|
|
2695
|
+
});
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
renderTimeline(pptxSlide, pptx, timeline, rect, theme) {
|
|
2699
|
+
const items = timeline.items || [];
|
|
2700
|
+
if (items.length === 0)
|
|
2701
|
+
return;
|
|
2702
|
+
const itemW = rect.w / items.length;
|
|
2703
|
+
const lineY = rect.y + 0.25;
|
|
2704
|
+
pptxSlide.addShape(pptx.ShapeType.rect, {
|
|
2705
|
+
x: rect.x + 0.2,
|
|
2706
|
+
y: lineY,
|
|
2707
|
+
w: rect.w - 0.4,
|
|
2708
|
+
h: 0.03,
|
|
2709
|
+
fill: { color: this.cleanHexColor(theme.colors.border) }
|
|
2710
|
+
});
|
|
2711
|
+
items.forEach((item, idx) => {
|
|
2712
|
+
const itemX = rect.x + idx * itemW;
|
|
2713
|
+
const dotX = itemX + itemW / 2 - 0.1;
|
|
2714
|
+
pptxSlide.addShape(pptx.ShapeType.roundRect, {
|
|
2715
|
+
x: dotX,
|
|
2716
|
+
y: lineY - 0.08,
|
|
2717
|
+
w: 0.2,
|
|
2718
|
+
h: 0.2,
|
|
2719
|
+
fill: { color: this.cleanHexColor(theme.colors.primary) },
|
|
2720
|
+
line: { color: this.cleanHexColor(theme.colors.background), width: 2 },
|
|
2721
|
+
rectRadius: 0.1
|
|
2722
|
+
});
|
|
2723
|
+
if (item.date) {
|
|
2724
|
+
pptxSlide.addText(item.date, {
|
|
2725
|
+
x: itemX,
|
|
2726
|
+
y: lineY + 0.18,
|
|
2727
|
+
w: itemW,
|
|
2728
|
+
h: 0.25,
|
|
2729
|
+
fontSize: 11,
|
|
2730
|
+
bold: true,
|
|
2731
|
+
color: this.cleanHexColor(theme.colors.accent || theme.colors.primary),
|
|
2732
|
+
fontFace: cleanFontFace(theme.typography.codeFont),
|
|
2733
|
+
align: "center"
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2736
|
+
const descText = item.description ? `
|
|
2737
|
+
${item.description}` : "";
|
|
2738
|
+
pptxSlide.addText(`${item.title}${descText}`, {
|
|
2739
|
+
x: itemX + 0.05,
|
|
2740
|
+
y: lineY + 0.45,
|
|
2741
|
+
w: itemW - 0.1,
|
|
2742
|
+
h: rect.h - 0.55,
|
|
2743
|
+
fontSize: 12,
|
|
2744
|
+
color: this.cleanHexColor(theme.colors.text),
|
|
2745
|
+
fontFace: cleanFontFace(theme.typography.bodyFont),
|
|
2746
|
+
align: "center",
|
|
2747
|
+
valign: "top"
|
|
2748
|
+
});
|
|
2749
|
+
});
|
|
2750
|
+
}
|
|
2751
|
+
renderCompare(pptxSlide, pptx, node, scaleX, scaleY, theme) {
|
|
2752
|
+
const { element, bounds } = node;
|
|
2753
|
+
const compare = element;
|
|
2754
|
+
const rect = this.toInches(bounds, scaleX, scaleY);
|
|
2755
|
+
const colW = (rect.w - 0.4) / 2;
|
|
2756
|
+
pptxSlide.addShape(pptx.ShapeType.roundRect, {
|
|
2757
|
+
x: rect.x,
|
|
2758
|
+
y: rect.y,
|
|
2759
|
+
w: colW,
|
|
2760
|
+
h: rect.h,
|
|
2761
|
+
fill: { color: this.cleanHexColor(theme.colors.surface) },
|
|
2762
|
+
line: { color: this.cleanHexColor(theme.colors.border), width: 1 },
|
|
2763
|
+
rectRadius: 0.1
|
|
2764
|
+
});
|
|
2765
|
+
if (compare.leftTitle) {
|
|
2766
|
+
pptxSlide.addText(compare.leftTitle, {
|
|
2767
|
+
x: rect.x + 0.15,
|
|
2768
|
+
y: rect.y + 0.15,
|
|
2769
|
+
w: colW - 0.3,
|
|
2770
|
+
h: 0.4,
|
|
2771
|
+
fontSize: 14,
|
|
2772
|
+
bold: true,
|
|
2773
|
+
color: this.cleanHexColor(theme.colors.primary),
|
|
2774
|
+
fontFace: cleanFontFace(theme.typography.headingFont)
|
|
2775
|
+
});
|
|
2776
|
+
}
|
|
2777
|
+
const rightX = rect.x + colW + 0.4;
|
|
2778
|
+
pptxSlide.addShape(pptx.ShapeType.roundRect, {
|
|
2779
|
+
x: rightX,
|
|
2780
|
+
y: rect.y,
|
|
2781
|
+
w: colW,
|
|
2782
|
+
h: rect.h,
|
|
2783
|
+
fill: { color: this.cleanHexColor(theme.colors.surface) },
|
|
2784
|
+
line: { color: this.cleanHexColor(theme.colors.border), width: 1 },
|
|
2785
|
+
rectRadius: 0.1
|
|
2786
|
+
});
|
|
2787
|
+
if (compare.rightTitle) {
|
|
2788
|
+
pptxSlide.addText(compare.rightTitle, {
|
|
2789
|
+
x: rightX + 0.15,
|
|
2790
|
+
y: rect.y + 0.15,
|
|
2791
|
+
w: colW - 0.3,
|
|
2792
|
+
h: 0.4,
|
|
2793
|
+
fontSize: 14,
|
|
2794
|
+
bold: true,
|
|
2795
|
+
color: this.cleanHexColor(theme.colors.primary),
|
|
2796
|
+
fontFace: cleanFontFace(theme.typography.headingFont)
|
|
2797
|
+
});
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
renderMermaid(pptxSlide, pptx, mermaid, rect, theme) {
|
|
2801
|
+
pptxSlide.addShape(pptx.ShapeType.roundRect, {
|
|
2802
|
+
x: rect.x,
|
|
2803
|
+
y: rect.y,
|
|
2804
|
+
w: rect.w,
|
|
2805
|
+
h: rect.h,
|
|
2806
|
+
fill: { color: this.cleanHexColor(theme.colors.surface) },
|
|
2807
|
+
line: { color: this.cleanHexColor(theme.colors.primary), width: 1 },
|
|
2808
|
+
rectRadius: 0.1
|
|
2809
|
+
});
|
|
2810
|
+
pptxSlide.addText(`[Diagram: Mermaid]
|
|
2811
|
+
|
|
2812
|
+
${mermaid.code}`, {
|
|
2813
|
+
x: rect.x + 0.2,
|
|
2814
|
+
y: rect.y + 0.2,
|
|
2815
|
+
w: rect.w - 0.4,
|
|
2816
|
+
h: rect.h - 0.4,
|
|
2817
|
+
fontSize: 12,
|
|
2818
|
+
color: this.cleanHexColor(theme.colors.text),
|
|
2819
|
+
fontFace: cleanFontFace(theme.typography.codeFont),
|
|
2820
|
+
align: "center",
|
|
2821
|
+
valign: "middle"
|
|
2822
|
+
});
|
|
2823
|
+
}
|
|
2361
2824
|
toInches(bounds, scaleX, scaleY) {
|
|
2362
2825
|
return {
|
|
2363
2826
|
x: Math.max(0, bounds.x * scaleX),
|
|
@@ -2460,7 +2923,43 @@ var HtmlRenderer = class {
|
|
|
2460
2923
|
<title>${this.escapeHtml(title)}</title>
|
|
2461
2924
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
2462
2925
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
2463
|
-
<
|
|
2926
|
+
<script type="module">
|
|
2927
|
+
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
|
2928
|
+
try {
|
|
2929
|
+
mermaid.initialize({
|
|
2930
|
+
startOnLoad: false,
|
|
2931
|
+
theme: 'dark',
|
|
2932
|
+
securityLevel: 'loose',
|
|
2933
|
+
themeVariables: {
|
|
2934
|
+
darkMode: true,
|
|
2935
|
+
background: '${theme.colors.background}',
|
|
2936
|
+
primaryColor: '${theme.colors.primary}',
|
|
2937
|
+
primaryTextColor: '#ffffff',
|
|
2938
|
+
primaryBorderColor: '${theme.colors.primary}',
|
|
2939
|
+
lineColor: '${theme.colors.accent || theme.colors.primary}',
|
|
2940
|
+
secondaryColor: '${theme.colors.surface}',
|
|
2941
|
+
tertiaryColor: '${theme.colors.surface}'
|
|
2942
|
+
}
|
|
2943
|
+
});
|
|
2944
|
+
window.mermaid = mermaid;
|
|
2945
|
+
window.renderMermaidInSlide = async function(slideEl) {
|
|
2946
|
+
if (!slideEl || !window.mermaid) return;
|
|
2947
|
+
const nodes = Array.from(slideEl.querySelectorAll('.mermaid:not([data-processed="true"])'));
|
|
2948
|
+
if (nodes.length > 0) {
|
|
2949
|
+
try {
|
|
2950
|
+
await window.mermaid.run({ nodes: nodes });
|
|
2951
|
+
} catch (e) {
|
|
2952
|
+
console.warn('Mermaid render notice:', e);
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
};
|
|
2956
|
+
// Auto-render visible slide if present
|
|
2957
|
+
const cur = document.querySelector('.yumia-slide-wrapper.active');
|
|
2958
|
+
if (cur) window.renderMermaidInSlide(cur);
|
|
2959
|
+
} catch (err) {
|
|
2960
|
+
console.warn('Mermaid load notice:', err);
|
|
2961
|
+
}
|
|
2962
|
+
</script>
|
|
2464
2963
|
<style>
|
|
2465
2964
|
:root {
|
|
2466
2965
|
--yumia-bg: ${theme.colors.background};
|
|
@@ -2843,6 +3342,194 @@ var HtmlRenderer = class {
|
|
|
2843
3342
|
transition: width 0.25s ease;
|
|
2844
3343
|
}
|
|
2845
3344
|
|
|
3345
|
+
/* Badge Directive */
|
|
3346
|
+
.yumia-badge {
|
|
3347
|
+
display: inline-flex;
|
|
3348
|
+
align-items: center;
|
|
3349
|
+
padding: 3px 10px;
|
|
3350
|
+
border-radius: 999px;
|
|
3351
|
+
font-size: 0.8rem;
|
|
3352
|
+
font-weight: 700;
|
|
3353
|
+
letter-spacing: 0.04em;
|
|
3354
|
+
text-transform: uppercase;
|
|
3355
|
+
background: rgba(255, 255, 255, 0.1);
|
|
3356
|
+
color: var(--yumia-text);
|
|
3357
|
+
border: 1px solid var(--yumia-border);
|
|
3358
|
+
margin-bottom: 0.5rem;
|
|
3359
|
+
}
|
|
3360
|
+
.yumia-badge.variant-primary { background: rgba(0, 240, 255, 0.15); color: var(--yumia-primary); border-color: var(--yumia-primary); }
|
|
3361
|
+
.yumia-badge.variant-success { background: rgba(16, 185, 129, 0.15); color: var(--yumia-success); border-color: var(--yumia-success); }
|
|
3362
|
+
.yumia-badge.variant-warning { background: rgba(245, 158, 11, 0.15); color: var(--yumia-warning); border-color: var(--yumia-warning); }
|
|
3363
|
+
.yumia-badge.variant-danger { background: rgba(239, 68, 68, 0.15); color: var(--yumia-danger); border-color: var(--yumia-danger); }
|
|
3364
|
+
.yumia-badge.variant-info { background: rgba(59, 130, 246, 0.15); color: var(--yumia-info); border-color: var(--yumia-info); }
|
|
3365
|
+
.yumia-badge.variant-accent { background: rgba(255, 46, 136, 0.15); color: var(--yumia-accent); border-color: var(--yumia-accent); }
|
|
3366
|
+
|
|
3367
|
+
/* Timeline Directive */
|
|
3368
|
+
.yumia-timeline {
|
|
3369
|
+
display: flex;
|
|
3370
|
+
gap: 16px;
|
|
3371
|
+
margin: 1.2rem 0;
|
|
3372
|
+
width: 100%;
|
|
3373
|
+
}
|
|
3374
|
+
.yumia-timeline.layout-horizontal {
|
|
3375
|
+
flex-direction: row;
|
|
3376
|
+
justify-content: space-between;
|
|
3377
|
+
position: relative;
|
|
3378
|
+
}
|
|
3379
|
+
.yumia-timeline.layout-horizontal::before {
|
|
3380
|
+
content: '';
|
|
3381
|
+
position: absolute;
|
|
3382
|
+
top: 18px;
|
|
3383
|
+
left: 20px;
|
|
3384
|
+
right: 20px;
|
|
3385
|
+
height: 2px;
|
|
3386
|
+
background: var(--yumia-border);
|
|
3387
|
+
z-index: 0;
|
|
3388
|
+
}
|
|
3389
|
+
.yumia-timeline-item {
|
|
3390
|
+
position: relative;
|
|
3391
|
+
z-index: 1;
|
|
3392
|
+
display: flex;
|
|
3393
|
+
flex-direction: column;
|
|
3394
|
+
align-items: center;
|
|
3395
|
+
text-align: center;
|
|
3396
|
+
flex: 1;
|
|
3397
|
+
}
|
|
3398
|
+
.yumia-timeline-dot {
|
|
3399
|
+
width: 14px;
|
|
3400
|
+
height: 14px;
|
|
3401
|
+
border-radius: 50%;
|
|
3402
|
+
background: var(--yumia-primary);
|
|
3403
|
+
border: 3px solid var(--yumia-bg);
|
|
3404
|
+
box-shadow: 0 0 10px var(--yumia-primary);
|
|
3405
|
+
margin-bottom: 10px;
|
|
3406
|
+
}
|
|
3407
|
+
.yumia-timeline-date {
|
|
3408
|
+
font-size: 0.85rem;
|
|
3409
|
+
font-weight: 700;
|
|
3410
|
+
color: var(--yumia-accent);
|
|
3411
|
+
margin-bottom: 4px;
|
|
3412
|
+
font-family: var(--yumia-font-code);
|
|
3413
|
+
}
|
|
3414
|
+
.yumia-timeline-title {
|
|
3415
|
+
font-size: 1.05rem;
|
|
3416
|
+
font-weight: 600;
|
|
3417
|
+
color: var(--yumia-text);
|
|
3418
|
+
margin-bottom: 4px;
|
|
3419
|
+
}
|
|
3420
|
+
.yumia-timeline-desc {
|
|
3421
|
+
font-size: 0.85rem;
|
|
3422
|
+
color: var(--yumia-muted);
|
|
3423
|
+
line-height: 1.4;
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3426
|
+
/* Compare Directive */
|
|
3427
|
+
.yumia-compare {
|
|
3428
|
+
display: grid;
|
|
3429
|
+
grid-template-columns: 1fr auto 1fr;
|
|
3430
|
+
gap: 20px;
|
|
3431
|
+
align-items: stretch;
|
|
3432
|
+
margin: 1.2rem 0;
|
|
3433
|
+
}
|
|
3434
|
+
.yumia-compare-col {
|
|
3435
|
+
background: var(--yumia-surface);
|
|
3436
|
+
border: 1px solid var(--yumia-border);
|
|
3437
|
+
border-radius: var(--yumia-radius-card);
|
|
3438
|
+
padding: 1.5rem;
|
|
3439
|
+
display: flex;
|
|
3440
|
+
flex-direction: column;
|
|
3441
|
+
}
|
|
3442
|
+
.yumia-compare-title {
|
|
3443
|
+
font-size: 1.2rem;
|
|
3444
|
+
font-weight: 700;
|
|
3445
|
+
color: var(--yumia-primary);
|
|
3446
|
+
margin-bottom: 1rem;
|
|
3447
|
+
padding-bottom: 0.5rem;
|
|
3448
|
+
border-bottom: 1px solid var(--yumia-divider);
|
|
3449
|
+
}
|
|
3450
|
+
.yumia-compare-divider {
|
|
3451
|
+
display: flex;
|
|
3452
|
+
align-items: center;
|
|
3453
|
+
justify-content: center;
|
|
3454
|
+
font-weight: 800;
|
|
3455
|
+
font-size: 0.9rem;
|
|
3456
|
+
color: var(--yumia-muted);
|
|
3457
|
+
background: rgba(255, 255, 255, 0.05);
|
|
3458
|
+
border-radius: 50%;
|
|
3459
|
+
width: 36px;
|
|
3460
|
+
height: 36px;
|
|
3461
|
+
align-self: center;
|
|
3462
|
+
border: 1px solid var(--yumia-border);
|
|
3463
|
+
}
|
|
3464
|
+
|
|
3465
|
+
/* Native SVG Chart Container */
|
|
3466
|
+
.yumia-chart-container {
|
|
3467
|
+
background: var(--yumia-surface);
|
|
3468
|
+
border: 1px solid var(--yumia-border);
|
|
3469
|
+
border-radius: var(--yumia-radius-card);
|
|
3470
|
+
padding: 1.25rem;
|
|
3471
|
+
margin: 1rem 0;
|
|
3472
|
+
display: flex;
|
|
3473
|
+
flex-direction: column;
|
|
3474
|
+
align-items: center;
|
|
3475
|
+
width: 100%;
|
|
3476
|
+
}
|
|
3477
|
+
.yumia-chart-title {
|
|
3478
|
+
font-size: 1.1rem;
|
|
3479
|
+
font-weight: 700;
|
|
3480
|
+
color: var(--yumia-text);
|
|
3481
|
+
margin-bottom: 0.75rem;
|
|
3482
|
+
align-self: flex-start;
|
|
3483
|
+
}
|
|
3484
|
+
|
|
3485
|
+
/* Mermaid Container */
|
|
3486
|
+
.mermaid-container {
|
|
3487
|
+
background: rgba(10, 10, 18, 0.6);
|
|
3488
|
+
border: 1.5px solid var(--yumia-border);
|
|
3489
|
+
border-radius: var(--yumia-radius-card);
|
|
3490
|
+
padding: 1.5rem;
|
|
3491
|
+
margin: 1rem 0;
|
|
3492
|
+
display: flex;
|
|
3493
|
+
justify-content: center;
|
|
3494
|
+
align-items: center;
|
|
3495
|
+
overflow: auto;
|
|
3496
|
+
width: 100%;
|
|
3497
|
+
min-height: 240px;
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3500
|
+
.mermaid-container pre.mermaid,
|
|
3501
|
+
.mermaid-container .mermaid {
|
|
3502
|
+
background: transparent !important;
|
|
3503
|
+
border: none !important;
|
|
3504
|
+
padding: 0 !important;
|
|
3505
|
+
margin: 0 !important;
|
|
3506
|
+
font-size: 1rem;
|
|
3507
|
+
color: #fff;
|
|
3508
|
+
display: flex;
|
|
3509
|
+
justify-content: center;
|
|
3510
|
+
align-items: center;
|
|
3511
|
+
width: 100%;
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
.mermaid-container svg {
|
|
3515
|
+
max-width: 100%;
|
|
3516
|
+
height: auto;
|
|
3517
|
+
max-height: 420px;
|
|
3518
|
+
}
|
|
3519
|
+
|
|
3520
|
+
/* Progressive Reveal (Step Builds) */
|
|
3521
|
+
.yumia-slide-wrapper [data-step] {
|
|
3522
|
+
transition: opacity 0.25s ease, transform 0.25s ease;
|
|
3523
|
+
}
|
|
3524
|
+
.yumia-slide-wrapper:not(.step-active) [data-step] {
|
|
3525
|
+
opacity: 0.2;
|
|
3526
|
+
transform: translateY(4px);
|
|
3527
|
+
}
|
|
3528
|
+
.yumia-slide-wrapper.step-active [data-step] {
|
|
3529
|
+
opacity: 1;
|
|
3530
|
+
transform: translateY(0);
|
|
3531
|
+
}
|
|
3532
|
+
|
|
2846
3533
|
/* Notes Drawer */
|
|
2847
3534
|
.yumia-notes-drawer {
|
|
2848
3535
|
position: fixed;
|
|
@@ -3154,6 +3841,12 @@ var HtmlRenderer = class {
|
|
|
3154
3841
|
if (broadcast && syncChannel) {
|
|
3155
3842
|
syncChannel.postMessage({ index: currentIdx });
|
|
3156
3843
|
}
|
|
3844
|
+
|
|
3845
|
+
setTimeout(() => {
|
|
3846
|
+
if (window.renderMermaidInSlide && slides[currentIdx]) {
|
|
3847
|
+
window.renderMermaidInSlide(slides[currentIdx]);
|
|
3848
|
+
}
|
|
3849
|
+
}, 50);
|
|
3157
3850
|
}
|
|
3158
3851
|
|
|
3159
3852
|
function openSpeakerWindow() {
|
|
@@ -3258,6 +3951,13 @@ var HtmlRenderer = class {
|
|
|
3258
3951
|
const rawNotes = slides[currentIdx].getAttribute('data-notes');
|
|
3259
3952
|
notesBox.innerHTML = rawNotes ? rawNotes : '<em style="color:var(--yumia-muted);">No notes provided for this slide.</em>';
|
|
3260
3953
|
}
|
|
3954
|
+
|
|
3955
|
+
setTimeout(() => {
|
|
3956
|
+
if (window.renderMermaidInSlide) {
|
|
3957
|
+
if (curBox) window.renderMermaidInSlide(curBox);
|
|
3958
|
+
if (nextBox) window.renderMermaidInSlide(nextBox);
|
|
3959
|
+
}
|
|
3960
|
+
}, 50);
|
|
3261
3961
|
}
|
|
3262
3962
|
|
|
3263
3963
|
window.addEventListener('keydown', (e) => {
|
|
@@ -3467,10 +4167,174 @@ var HtmlRenderer = class {
|
|
|
3467
4167
|
}).join("\n");
|
|
3468
4168
|
return `<div class="yumia-columns" style="grid-template-columns: ${ratioTemplate};">${colsHtml}</div>`;
|
|
3469
4169
|
}
|
|
4170
|
+
case "badge": {
|
|
4171
|
+
return this.renderBadge(element);
|
|
4172
|
+
}
|
|
4173
|
+
case "mermaid": {
|
|
4174
|
+
const m = element;
|
|
4175
|
+
return `
|
|
4176
|
+
<div class="mermaid-container">
|
|
4177
|
+
<pre class="mermaid">${this.escapeHtml(m.code)}</pre>
|
|
4178
|
+
</div>`;
|
|
4179
|
+
}
|
|
4180
|
+
case "chart": {
|
|
4181
|
+
return this.renderChart(element, theme);
|
|
4182
|
+
}
|
|
4183
|
+
case "timeline": {
|
|
4184
|
+
return this.renderTimeline(element);
|
|
4185
|
+
}
|
|
4186
|
+
case "compare": {
|
|
4187
|
+
return this.renderCompare(element, theme);
|
|
4188
|
+
}
|
|
3470
4189
|
default:
|
|
3471
4190
|
return "";
|
|
3472
4191
|
}
|
|
3473
4192
|
}
|
|
4193
|
+
renderBadge(b) {
|
|
4194
|
+
const variant = b.variant || "default";
|
|
4195
|
+
return `<span class="yumia-badge variant-${variant}">${this.escapeHtml(b.text)}</span>`;
|
|
4196
|
+
}
|
|
4197
|
+
renderTimeline(t) {
|
|
4198
|
+
const layout = t.layout || "horizontal";
|
|
4199
|
+
const itemsHtml = t.items.map((item) => {
|
|
4200
|
+
const dateHtml = item.date ? `<div class="yumia-timeline-date">${this.escapeHtml(item.date)}</div>` : "";
|
|
4201
|
+
const descHtml = item.description ? `<div class="yumia-timeline-desc">${this.formatInline(item.description)}</div>` : "";
|
|
4202
|
+
return `
|
|
4203
|
+
<div class="yumia-timeline-item">
|
|
4204
|
+
<div class="yumia-timeline-dot"></div>
|
|
4205
|
+
${dateHtml}
|
|
4206
|
+
<div class="yumia-timeline-title">${this.formatInline(item.title)}</div>
|
|
4207
|
+
${descHtml}
|
|
4208
|
+
</div>`;
|
|
4209
|
+
}).join("\n");
|
|
4210
|
+
return `<div class="yumia-timeline layout-${layout}">${itemsHtml}</div>`;
|
|
4211
|
+
}
|
|
4212
|
+
renderCompare(c, theme) {
|
|
4213
|
+
const leftTitle = c.leftTitle ? `<div class="yumia-compare-title">${this.escapeHtml(c.leftTitle)}</div>` : "";
|
|
4214
|
+
const rightTitle = c.rightTitle ? `<div class="yumia-compare-title">${this.escapeHtml(c.rightTitle)}</div>` : "";
|
|
4215
|
+
const leftInner = c.left.map((el) => this.renderElement(el, theme)).join("\n");
|
|
4216
|
+
const rightInner = c.right.map((el) => this.renderElement(el, theme)).join("\n");
|
|
4217
|
+
return `
|
|
4218
|
+
<div class="yumia-compare">
|
|
4219
|
+
<div class="yumia-compare-col left">
|
|
4220
|
+
${leftTitle}
|
|
4221
|
+
${leftInner}
|
|
4222
|
+
</div>
|
|
4223
|
+
<div class="yumia-compare-divider">VS</div>
|
|
4224
|
+
<div class="yumia-compare-col right">
|
|
4225
|
+
${rightTitle}
|
|
4226
|
+
${rightInner}
|
|
4227
|
+
</div>
|
|
4228
|
+
</div>`;
|
|
4229
|
+
}
|
|
4230
|
+
renderChart(c, theme) {
|
|
4231
|
+
const titleHtml = c.title ? `<div class="yumia-chart-title">${this.escapeHtml(c.title)}</div>` : "";
|
|
4232
|
+
const labels = c.labels || [];
|
|
4233
|
+
const series = c.series || [];
|
|
4234
|
+
const colors = [
|
|
4235
|
+
theme.colors.primary || "#00F0FF",
|
|
4236
|
+
theme.colors.accent || "#FF2E88",
|
|
4237
|
+
theme.colors.secondary || "#7B2CBF",
|
|
4238
|
+
theme.colors.success || "#10B981",
|
|
4239
|
+
theme.colors.warning || "#F59E0B"
|
|
4240
|
+
];
|
|
4241
|
+
if (c.chartType === "line") {
|
|
4242
|
+
const allValues = series.flatMap((s) => s.values);
|
|
4243
|
+
const maxVal2 = Math.max(...allValues, 1);
|
|
4244
|
+
const width2 = 500;
|
|
4245
|
+
const height2 = 180;
|
|
4246
|
+
const padding2 = 35;
|
|
4247
|
+
const plotW2 = width2 - padding2 * 2;
|
|
4248
|
+
const plotH2 = height2 - padding2 * 2;
|
|
4249
|
+
let pathsHtml = "";
|
|
4250
|
+
series.forEach((s, sIdx) => {
|
|
4251
|
+
const sColor = s.color || colors[sIdx % colors.length];
|
|
4252
|
+
const pts = s.values.map((v, i) => {
|
|
4253
|
+
const x = padding2 + i / Math.max(s.values.length - 1, 1) * plotW2;
|
|
4254
|
+
const y = height2 - padding2 - v / maxVal2 * plotH2;
|
|
4255
|
+
return `${x},${y}`;
|
|
4256
|
+
});
|
|
4257
|
+
const pointsStr = pts.join(" ");
|
|
4258
|
+
const circles = pts.map((pt) => `<circle cx="${pt.split(",")[0]}" cy="${pt.split(",")[1]}" r="4" fill="${sColor}" />`).join("");
|
|
4259
|
+
pathsHtml += `
|
|
4260
|
+
<polyline fill="none" stroke="${sColor}" stroke-width="3" stroke-linecap="round" points="${pointsStr}" />
|
|
4261
|
+
${circles}`;
|
|
4262
|
+
});
|
|
4263
|
+
const labelTexts = labels.map((l, i) => {
|
|
4264
|
+
const x = padding2 + i / Math.max(labels.length - 1, 1) * plotW2;
|
|
4265
|
+
return `<text x="${x}" y="${height2 - 10}" text-anchor="middle" fill="${theme.colors.muted || "#94a3b8"}" font-size="11" font-family="sans-serif">${this.escapeHtml(l)}</text>`;
|
|
4266
|
+
}).join("");
|
|
4267
|
+
return `
|
|
4268
|
+
<div class="yumia-chart-container">
|
|
4269
|
+
${titleHtml}
|
|
4270
|
+
<svg viewBox="0 0 ${width2} ${height2}" style="width:100%; max-height:220px;">
|
|
4271
|
+
<line x1="${padding2}" y1="${height2 - padding2}" x2="${width2 - padding2}" y2="${height2 - padding2}" stroke="rgba(255,255,255,0.15)" stroke-width="1" />
|
|
4272
|
+
${pathsHtml}
|
|
4273
|
+
${labelTexts}
|
|
4274
|
+
</svg>
|
|
4275
|
+
</div>`;
|
|
4276
|
+
}
|
|
4277
|
+
if (c.chartType === "pie" || c.chartType === "doughnut") {
|
|
4278
|
+
const values2 = series[0]?.values || [];
|
|
4279
|
+
const total = values2.reduce((a, b) => a + b, 0) || 1;
|
|
4280
|
+
let cumulativePercent = 0;
|
|
4281
|
+
const radius = 60;
|
|
4282
|
+
const cx = 100;
|
|
4283
|
+
const cy = 100;
|
|
4284
|
+
const strokeWidth = c.chartType === "doughnut" ? 24 : 60;
|
|
4285
|
+
const circ = 2 * Math.PI * radius;
|
|
4286
|
+
const slices = values2.map((val, i) => {
|
|
4287
|
+
const percent = val / total;
|
|
4288
|
+
const strokeDasharray = `${percent * circ} ${circ}`;
|
|
4289
|
+
const strokeDashoffset = -cumulativePercent * circ;
|
|
4290
|
+
cumulativePercent += percent;
|
|
4291
|
+
const sColor = colors[i % colors.length];
|
|
4292
|
+
return `<circle cx="${cx}" cy="${cy}" r="${radius}" fill="none" stroke="${sColor}" stroke-width="${strokeWidth}" stroke-dasharray="${strokeDasharray}" stroke-dashoffset="${strokeDashoffset}" />`;
|
|
4293
|
+
}).join("");
|
|
4294
|
+
const legend = labels.map((l, i) => {
|
|
4295
|
+
const sColor = colors[i % colors.length];
|
|
4296
|
+
const pct = Math.round((values2[i] || 0) / total * 100);
|
|
4297
|
+
return `<div style="display:flex; align-items:center; gap:8px; font-size:12px; margin:4px 0;"><span style="width:10px; height:10px; border-radius:50%; background:${sColor};"></span><span style="color:var(--yumia-text);">${this.escapeHtml(l)} (${pct}%)</span></div>`;
|
|
4298
|
+
}).join("");
|
|
4299
|
+
return `
|
|
4300
|
+
<div class="yumia-chart-container">
|
|
4301
|
+
${titleHtml}
|
|
4302
|
+
<div style="display:flex; align-items:center; justify-content:center; gap:28px; width:100%;">
|
|
4303
|
+
<svg viewBox="0 0 200 200" style="width:160px; height:160px; transform: rotate(-90deg);">
|
|
4304
|
+
${slices}
|
|
4305
|
+
</svg>
|
|
4306
|
+
<div style="display:flex; flex-direction:column;">${legend}</div>
|
|
4307
|
+
</div>
|
|
4308
|
+
</div>`;
|
|
4309
|
+
}
|
|
4310
|
+
const values = series[0]?.values || [];
|
|
4311
|
+
const maxVal = Math.max(...values, 1);
|
|
4312
|
+
const width = 500;
|
|
4313
|
+
const height = 180;
|
|
4314
|
+
const padding = 35;
|
|
4315
|
+
const plotW = width - padding * 2;
|
|
4316
|
+
const plotH = height - padding * 2;
|
|
4317
|
+
const barWidth = Math.min(48, Math.max(16, plotW / Math.max(values.length, 1) * 0.6));
|
|
4318
|
+
const bars = values.map((val, i) => {
|
|
4319
|
+
const x = padding + (i + 0.5) * (plotW / Math.max(values.length, 1)) - barWidth / 2;
|
|
4320
|
+
const barH = val / maxVal * plotH;
|
|
4321
|
+
const y = height - padding - barH;
|
|
4322
|
+
const color = colors[i % colors.length];
|
|
4323
|
+
const label = labels[i] || "";
|
|
4324
|
+
return `
|
|
4325
|
+
<rect x="${x}" y="${y}" width="${barWidth}" height="${barH}" rx="4" fill="${color}" opacity="0.9" />
|
|
4326
|
+
<text x="${x + barWidth / 2}" y="${y - 6}" text-anchor="middle" fill="${color}" font-size="11" font-weight="600" font-family="sans-serif">${val}</text>
|
|
4327
|
+
<text x="${x + barWidth / 2}" y="${height - 12}" text-anchor="middle" fill="${theme.colors.muted || "#94a3b8"}" font-size="11" font-family="sans-serif">${this.escapeHtml(label)}</text>`;
|
|
4328
|
+
}).join("");
|
|
4329
|
+
return `
|
|
4330
|
+
<div class="yumia-chart-container">
|
|
4331
|
+
${titleHtml}
|
|
4332
|
+
<svg viewBox="0 0 ${width} ${height}" style="width:100%; max-height:220px;">
|
|
4333
|
+
<line x1="${padding}" y1="${height - padding}" x2="${width - padding}" y2="${height - padding}" stroke="rgba(255,255,255,0.15)" stroke-width="1" />
|
|
4334
|
+
${bars}
|
|
4335
|
+
</svg>
|
|
4336
|
+
</div>`;
|
|
4337
|
+
}
|
|
3474
4338
|
formatInline(text) {
|
|
3475
4339
|
const escaped = this.escapeHtml(text);
|
|
3476
4340
|
return escaped.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>").replace(/\*(.*?)\*/g, "<em>$1</em>").replace(/`(.*?)`/g, "<code>$1</code>");
|
|
@@ -3718,6 +4582,117 @@ var PdfRenderer = class {
|
|
|
3718
4582
|
doc.rect(x, y, width, curY - y).strokeColor(theme.colors.border || "rgba(255,255,255,0.1)").stroke();
|
|
3719
4583
|
return curY;
|
|
3720
4584
|
}
|
|
4585
|
+
case "badge": {
|
|
4586
|
+
const b = element;
|
|
4587
|
+
const variantColor = this.getVariantColor(b.variant, theme);
|
|
4588
|
+
const text = this.stripFormatting(b.text).toUpperCase();
|
|
4589
|
+
const badgeW = Math.min(180, Math.max(60, text.length * 7 + 20));
|
|
4590
|
+
const badgeH = 22;
|
|
4591
|
+
doc.roundedRect(x, y, badgeW, badgeH, 11).fill(theme.colors.surface || "rgba(255,255,255,0.08)");
|
|
4592
|
+
doc.roundedRect(x, y, badgeW, badgeH, 11).lineWidth(1).strokeColor(variantColor).stroke();
|
|
4593
|
+
doc.font("Helvetica-Bold").fontSize(10).fillColor(variantColor).text(text, x, y + 6, { width: badgeW, align: "center" });
|
|
4594
|
+
return y + badgeH + 6;
|
|
4595
|
+
}
|
|
4596
|
+
case "timeline": {
|
|
4597
|
+
const t = element;
|
|
4598
|
+
const items = t.items || [];
|
|
4599
|
+
if (items.length === 0)
|
|
4600
|
+
return y;
|
|
4601
|
+
const itemW = (width - (items.length - 1) * 12) / items.length;
|
|
4602
|
+
const lineY = y + 14;
|
|
4603
|
+
doc.moveTo(x + 10, lineY).lineTo(x + width - 10, lineY).lineWidth(2).strokeColor(theme.colors.border || "rgba(255,255,255,0.2)").stroke();
|
|
4604
|
+
let maxItemH = 60;
|
|
4605
|
+
items.forEach((item, idx) => {
|
|
4606
|
+
const itemX = x + idx * (itemW + 12);
|
|
4607
|
+
const dotX = itemX + itemW / 2;
|
|
4608
|
+
doc.circle(dotX, lineY, 6).fill(theme.colors.primary);
|
|
4609
|
+
let curItemY = lineY + 12;
|
|
4610
|
+
if (item.date) {
|
|
4611
|
+
doc.font("Helvetica-Bold").fontSize(10).fillColor(theme.colors.accent || theme.colors.primary).text(this.stripFormatting(item.date), itemX, curItemY, {
|
|
4612
|
+
width: itemW,
|
|
4613
|
+
align: "center"
|
|
4614
|
+
});
|
|
4615
|
+
curItemY += 14;
|
|
4616
|
+
}
|
|
4617
|
+
doc.font("Helvetica-Bold").fontSize(12).fillColor(theme.colors.text).text(this.stripFormatting(item.title), itemX, curItemY, {
|
|
4618
|
+
width: itemW,
|
|
4619
|
+
align: "center"
|
|
4620
|
+
});
|
|
4621
|
+
curItemY += 16;
|
|
4622
|
+
if (item.description) {
|
|
4623
|
+
doc.font("Helvetica").fontSize(9).fillColor(theme.colors.muted || "#888888").text(this.stripFormatting(item.description), itemX, curItemY, {
|
|
4624
|
+
width: itemW,
|
|
4625
|
+
align: "center"
|
|
4626
|
+
});
|
|
4627
|
+
curItemY += 24;
|
|
4628
|
+
}
|
|
4629
|
+
if (curItemY - y > maxItemH)
|
|
4630
|
+
maxItemH = curItemY - y;
|
|
4631
|
+
});
|
|
4632
|
+
return y + maxItemH + 8;
|
|
4633
|
+
}
|
|
4634
|
+
case "compare": {
|
|
4635
|
+
const c = element;
|
|
4636
|
+
const colW = (width - 24) / 2;
|
|
4637
|
+
let leftY = y + 12;
|
|
4638
|
+
let rightY = y + 12;
|
|
4639
|
+
if (c.leftTitle) {
|
|
4640
|
+
doc.font("Helvetica-Bold").fontSize(14).fillColor(theme.colors.primary).text(this.stripFormatting(c.leftTitle), x + 12, leftY, { width: colW - 24 });
|
|
4641
|
+
leftY += 22;
|
|
4642
|
+
}
|
|
4643
|
+
for (const el of c.left) {
|
|
4644
|
+
leftY = this.renderElement(doc, el, x + 12, leftY, colW - 24, theme) + 6;
|
|
4645
|
+
}
|
|
4646
|
+
const rightX = x + colW + 24;
|
|
4647
|
+
if (c.rightTitle) {
|
|
4648
|
+
doc.font("Helvetica-Bold").fontSize(14).fillColor(theme.colors.primary).text(this.stripFormatting(c.rightTitle), rightX + 12, rightY, { width: colW - 24 });
|
|
4649
|
+
rightY += 22;
|
|
4650
|
+
}
|
|
4651
|
+
for (const el of c.right) {
|
|
4652
|
+
rightY = this.renderElement(doc, el, rightX + 12, rightY, colW - 24, theme) + 6;
|
|
4653
|
+
}
|
|
4654
|
+
const totalH = Math.max(leftY - y, rightY - y, 60) + 12;
|
|
4655
|
+
doc.roundedRect(x, y, colW, totalH, 8).strokeColor(theme.colors.border || "rgba(255,255,255,0.15)").stroke();
|
|
4656
|
+
doc.roundedRect(rightX, y, colW, totalH, 8).strokeColor(theme.colors.border || "rgba(255,255,255,0.15)").stroke();
|
|
4657
|
+
return y + totalH + 8;
|
|
4658
|
+
}
|
|
4659
|
+
case "chart": {
|
|
4660
|
+
const ch = element;
|
|
4661
|
+
const boxH = 130;
|
|
4662
|
+
doc.roundedRect(x, y, width, boxH, 8).fill(theme.colors.surface || "rgba(255,255,255,0.04)");
|
|
4663
|
+
doc.roundedRect(x, y, width, boxH, 8).strokeColor(theme.colors.border || "rgba(255,255,255,0.1)").stroke();
|
|
4664
|
+
let topY = y + 10;
|
|
4665
|
+
if (ch.title) {
|
|
4666
|
+
doc.font("Helvetica-Bold").fontSize(13).fillColor(theme.colors.text).text(this.stripFormatting(ch.title), x + 14, topY, { width: width - 28 });
|
|
4667
|
+
topY += 20;
|
|
4668
|
+
}
|
|
4669
|
+
const values = ch.series[0]?.values || [];
|
|
4670
|
+
const maxVal = Math.max(...values, 1);
|
|
4671
|
+
const plotH = boxH - (topY - y) - 28;
|
|
4672
|
+
const barW = Math.min(40, (width - 40) / Math.max(values.length, 1) * 0.6);
|
|
4673
|
+
values.forEach((val, idx) => {
|
|
4674
|
+
const barX = x + 24 + idx * ((width - 48) / Math.max(values.length, 1));
|
|
4675
|
+
const h = val / maxVal * plotH;
|
|
4676
|
+
const barY = topY + plotH - h;
|
|
4677
|
+
doc.rect(barX, barY, barW, h).fill(theme.colors.primary);
|
|
4678
|
+
doc.font("Helvetica").fontSize(9).fillColor(theme.colors.text).text(String(val), barX, barY - 12, { width: barW, align: "center" });
|
|
4679
|
+
if (ch.labels[idx]) {
|
|
4680
|
+
doc.font("Helvetica").fontSize(9).fillColor(theme.colors.muted || "#888888").text(this.stripFormatting(ch.labels[idx]), barX - 10, topY + plotH + 4, {
|
|
4681
|
+
width: barW + 20,
|
|
4682
|
+
align: "center"
|
|
4683
|
+
});
|
|
4684
|
+
}
|
|
4685
|
+
});
|
|
4686
|
+
return y + boxH + 8;
|
|
4687
|
+
}
|
|
4688
|
+
case "mermaid": {
|
|
4689
|
+
const m = element;
|
|
4690
|
+
const boxH = 90;
|
|
4691
|
+
doc.roundedRect(x, y, width, boxH, 8).fill(theme.colors.surface || "rgba(255,255,255,0.04)");
|
|
4692
|
+
doc.roundedRect(x, y, width, boxH, 8).strokeColor(theme.colors.primary).stroke();
|
|
4693
|
+
doc.font("Courier").fontSize(11).fillColor(theme.colors.text).text(this.stripFormatting(m.code), x + 12, y + 12, { width: width - 24 });
|
|
4694
|
+
return y + boxH + 8;
|
|
4695
|
+
}
|
|
3721
4696
|
default:
|
|
3722
4697
|
return y;
|
|
3723
4698
|
}
|
|
@@ -3849,7 +4824,7 @@ function startDevServer(filePath, options = {}) {
|
|
|
3849
4824
|
// src/cli.ts
|
|
3850
4825
|
import { mkdirSync, readFileSync as readFileSync2, watch as fsWatch, writeFileSync } from "fs";
|
|
3851
4826
|
import { basename, dirname, extname, join, resolve as resolve2 } from "path";
|
|
3852
|
-
var VERSION = "0.1.
|
|
4827
|
+
var VERSION = "0.1.17";
|
|
3853
4828
|
function printHelp() {
|
|
3854
4829
|
return `
|
|
3855
4830
|
YumiaMD \u2014 Markdown-based presentation compiler (v${VERSION})
|
|
@@ -3866,6 +4841,7 @@ Commands:
|
|
|
3866
4841
|
inspect <file> Inspect the AST and geometric layout tree
|
|
3867
4842
|
schema Output machine-readable JSON schema for AI agents
|
|
3868
4843
|
build <file> Compile a presentation to PowerPoint (.pptx), PDF (.pdf), or HTML (.html)
|
|
4844
|
+
deploy <file> Export and deploy presentation to static site, GitHub Pages, or Vercel
|
|
3869
4845
|
|
|
3870
4846
|
Theming & Color Options:
|
|
3871
4847
|
--theme, -t <name> Base theme: default | cyberpunk | minimal | corporate | terminal | academic
|
|
@@ -4196,6 +5172,68 @@ ${summary}${isStrict && report.warnings.length > 0 ? " (failed due to --strict)"
|
|
|
4196
5172
|
};
|
|
4197
5173
|
}
|
|
4198
5174
|
}
|
|
5175
|
+
if (command === "deploy") {
|
|
5176
|
+
if (!target) {
|
|
5177
|
+
const msg = "Error: Please specify a presentation file to deploy (e.g. 'yumia deploy presentation.yumia.md')";
|
|
5178
|
+
return { exitCode: 1, output: isJson ? JSON.stringify({ error: msg }) : msg };
|
|
5179
|
+
}
|
|
5180
|
+
try {
|
|
5181
|
+
const resolvedInput = resolve2(process.cwd(), target);
|
|
5182
|
+
const source = readFileSync2(resolvedInput, "utf-8");
|
|
5183
|
+
const provider = (getFlagValue(args, ["--provider"]) || "static").toLowerCase();
|
|
5184
|
+
const outDir = resolve2(process.cwd(), getFlagValue(args, ["--out", "-o"]) || "dist-site");
|
|
5185
|
+
mkdirSync(outDir, { recursive: true });
|
|
5186
|
+
const compiler = new YumiaCompiler();
|
|
5187
|
+
const htmlRenderer = new HtmlRenderer();
|
|
5188
|
+
const result = await compiler.compile(source, htmlRenderer);
|
|
5189
|
+
const indexPath = join(outDir, "index.html");
|
|
5190
|
+
writeFileSync(indexPath, result.html, "utf-8");
|
|
5191
|
+
if (provider === "gh-pages" || provider === "github") {
|
|
5192
|
+
writeFileSync(join(outDir, ".nojekyll"), "", "utf-8");
|
|
5193
|
+
} else if (provider === "vercel") {
|
|
5194
|
+
const vercelConfig = {
|
|
5195
|
+
version: 2,
|
|
5196
|
+
cleanUrls: true,
|
|
5197
|
+
routes: [{ src: "/(.*)", dest: "/index.html" }]
|
|
5198
|
+
};
|
|
5199
|
+
writeFileSync(join(outDir, "vercel.json"), JSON.stringify(vercelConfig, null, 2), "utf-8");
|
|
5200
|
+
}
|
|
5201
|
+
if (isJson) {
|
|
5202
|
+
return {
|
|
5203
|
+
exitCode: 0,
|
|
5204
|
+
output: JSON.stringify(
|
|
5205
|
+
{
|
|
5206
|
+
success: true,
|
|
5207
|
+
provider,
|
|
5208
|
+
outputDirectory: outDir,
|
|
5209
|
+
indexPath,
|
|
5210
|
+
slideCount: result.slideCount
|
|
5211
|
+
},
|
|
5212
|
+
null,
|
|
5213
|
+
2
|
|
5214
|
+
)
|
|
5215
|
+
};
|
|
5216
|
+
}
|
|
5217
|
+
return {
|
|
5218
|
+
exitCode: 0,
|
|
5219
|
+
output: [
|
|
5220
|
+
`\u{1F680} YumiaMD Presentation Deployment Ready!`,
|
|
5221
|
+
`\u2713 Standalone interactive deck compiled (${result.slideCount} slides)`,
|
|
5222
|
+
`\u2713 Target Directory: ${outDir}`,
|
|
5223
|
+
`\u2713 Provider Profile: ${provider}`,
|
|
5224
|
+
`\u2713 Entrypoint: ${indexPath}`,
|
|
5225
|
+
``,
|
|
5226
|
+
provider === "gh-pages" ? `To publish to GitHub Pages: push '${outDir}' contents to 'gh-pages' branch.` : `To deploy to Vercel/Netlify/S3: run 'vercel ${outDir}' or host files from '${outDir}'.`
|
|
5227
|
+
].join("\n")
|
|
5228
|
+
};
|
|
5229
|
+
} catch (err) {
|
|
5230
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5231
|
+
if (isJson) {
|
|
5232
|
+
return { exitCode: 1, output: JSON.stringify({ success: false, error: msg }) };
|
|
5233
|
+
}
|
|
5234
|
+
return { exitCode: 1, output: `\u2717 Deployment build failed: ${msg}` };
|
|
5235
|
+
}
|
|
5236
|
+
}
|
|
4199
5237
|
if (command === "build" || command === "watch") {
|
|
4200
5238
|
if (!target) {
|
|
4201
5239
|
const msg = `Error: Please specify a presentation file to ${command}.`;
|
|
@@ -4314,6 +5352,11 @@ export {
|
|
|
4314
5352
|
createCode,
|
|
4315
5353
|
createQuote,
|
|
4316
5354
|
createTable,
|
|
5355
|
+
createChart,
|
|
5356
|
+
createMermaid,
|
|
5357
|
+
createTimeline,
|
|
5358
|
+
createCompare,
|
|
5359
|
+
createBadge,
|
|
4317
5360
|
createGroup,
|
|
4318
5361
|
createColumn,
|
|
4319
5362
|
createColumns,
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export * from '@yumiamd/renderer-pptx';
|
|
|
9
9
|
export * from '@yumiamd/renderer-html';
|
|
10
10
|
export * from '@yumiamd/renderer-pdf';
|
|
11
11
|
|
|
12
|
-
declare const VERSION = "0.1.
|
|
12
|
+
declare const VERSION = "0.1.17";
|
|
13
13
|
declare function printHelp(): string;
|
|
14
14
|
declare function runCli(argv: string[]): Promise<{
|
|
15
15
|
exitCode: number;
|
package/dist/index.js
CHANGED
|
@@ -13,15 +13,19 @@ import {
|
|
|
13
13
|
academicTheme,
|
|
14
14
|
cleanFontFace,
|
|
15
15
|
corporateTheme,
|
|
16
|
+
createBadge,
|
|
16
17
|
createCard,
|
|
18
|
+
createChart,
|
|
17
19
|
createCode,
|
|
18
20
|
createColumn,
|
|
19
21
|
createColumns,
|
|
22
|
+
createCompare,
|
|
20
23
|
createGroup,
|
|
21
24
|
createHeading,
|
|
22
25
|
createImage,
|
|
23
26
|
createLayoutDirective,
|
|
24
27
|
createList,
|
|
28
|
+
createMermaid,
|
|
25
29
|
createMetric,
|
|
26
30
|
createParagraph,
|
|
27
31
|
createPresentation,
|
|
@@ -29,6 +33,7 @@ import {
|
|
|
29
33
|
createSlide,
|
|
30
34
|
createTable,
|
|
31
35
|
createTheme,
|
|
36
|
+
createTimeline,
|
|
32
37
|
cyberpunkTheme,
|
|
33
38
|
defaultTheme,
|
|
34
39
|
minimalTheme,
|
|
@@ -39,7 +44,7 @@ import {
|
|
|
39
44
|
runCli,
|
|
40
45
|
startDevServer,
|
|
41
46
|
terminalTheme
|
|
42
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-IAEXC5SG.js";
|
|
43
48
|
export {
|
|
44
49
|
DEFAULT_VIEWPORT,
|
|
45
50
|
DefaultLayoutEngine,
|
|
@@ -55,15 +60,19 @@ export {
|
|
|
55
60
|
academicTheme,
|
|
56
61
|
cleanFontFace,
|
|
57
62
|
corporateTheme,
|
|
63
|
+
createBadge,
|
|
58
64
|
createCard,
|
|
65
|
+
createChart,
|
|
59
66
|
createCode,
|
|
60
67
|
createColumn,
|
|
61
68
|
createColumns,
|
|
69
|
+
createCompare,
|
|
62
70
|
createGroup,
|
|
63
71
|
createHeading,
|
|
64
72
|
createImage,
|
|
65
73
|
createLayoutDirective,
|
|
66
74
|
createList,
|
|
75
|
+
createMermaid,
|
|
67
76
|
createMetric,
|
|
68
77
|
createParagraph,
|
|
69
78
|
createPresentation,
|
|
@@ -71,6 +80,7 @@ export {
|
|
|
71
80
|
createSlide,
|
|
72
81
|
createTable,
|
|
73
82
|
createTheme,
|
|
83
|
+
createTimeline,
|
|
74
84
|
cyberpunkTheme,
|
|
75
85
|
defaultTheme,
|
|
76
86
|
minimalTheme,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yumiamd",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"description": "Command line interface and compiler for YumiaMD presentations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,15 +21,15 @@
|
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"tsup": "^8.5.1",
|
|
24
|
-
"@yumiamd/ast": "0.1.
|
|
25
|
-
"@yumiamd/
|
|
26
|
-
"@yumiamd/
|
|
27
|
-
"@yumiamd/
|
|
28
|
-
"@yumiamd/renderer": "0.1.
|
|
29
|
-
"@yumiamd/
|
|
30
|
-
"@yumiamd/
|
|
31
|
-
"@yumiamd/
|
|
32
|
-
"@yumiamd/renderer-pdf": "0.1.
|
|
24
|
+
"@yumiamd/ast": "0.1.17",
|
|
25
|
+
"@yumiamd/core": "0.1.17",
|
|
26
|
+
"@yumiamd/renderer": "0.1.17",
|
|
27
|
+
"@yumiamd/parser": "0.1.17",
|
|
28
|
+
"@yumiamd/renderer-html": "0.1.17",
|
|
29
|
+
"@yumiamd/theme": "0.1.17",
|
|
30
|
+
"@yumiamd/layout": "0.1.17",
|
|
31
|
+
"@yumiamd/renderer-pptx": "0.1.17",
|
|
32
|
+
"@yumiamd/renderer-pdf": "0.1.17"
|
|
33
33
|
},
|
|
34
34
|
"keywords": [
|
|
35
35
|
"yumia",
|