canva-pptx 1.0.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.
Files changed (87) hide show
  1. package/README.md +1147 -0
  2. package/package.json +63 -0
  3. package/src/AdvancedComponents/accordionList.js +39 -0
  4. package/src/AdvancedComponents/calendarGrid.js +50 -0
  5. package/src/AdvancedComponents/certificateFrame.js +35 -0
  6. package/src/AdvancedComponents/deviceMockup.js +59 -0
  7. package/src/AdvancedComponents/featureGrid.js +70 -0
  8. package/src/AdvancedComponents/funnelDiagram.js +49 -0
  9. package/src/AdvancedComponents/ganttChart.js +35 -0
  10. package/src/AdvancedComponents/invoiceTable.js +32 -0
  11. package/src/AdvancedComponents/matrixGrid.js +43 -0
  12. package/src/AdvancedComponents/mindMap.js +43 -0
  13. package/src/AdvancedComponents/orgChart.js +76 -0
  14. package/src/AdvancedComponents/personaCard.js +44 -0
  15. package/src/AdvancedComponents/processCycle.js +47 -0
  16. package/src/AdvancedComponents/pyramidHierarchy.js +38 -0
  17. package/src/AdvancedComponents/saasFeatureBlock.js +38 -0
  18. package/src/AdvancedComponents/swotMatrix.js +55 -0
  19. package/src/AdvancedComponents/teamMemberProfile.js +75 -0
  20. package/src/AdvancedComponents/trafficLight.js +35 -0
  21. package/src/AdvancedComponents/vennDiagram.js +35 -0
  22. package/src/AdvancedComponents/winLossChart.js +43 -0
  23. package/src/components/StatMetric.js +43 -0
  24. package/src/components/alertBox.js +46 -0
  25. package/src/components/avatarGroup.js +56 -0
  26. package/src/components/badge.js +40 -0
  27. package/src/components/breadcrumbNav.js +31 -0
  28. package/src/components/browserWindow.js +86 -0
  29. package/src/components/brushStroke.js +23 -0
  30. package/src/components/callToAction.js +27 -0
  31. package/src/components/card.js +64 -0
  32. package/src/components/chart.js +19 -0
  33. package/src/components/codeBlock.js +40 -0
  34. package/src/components/codeDiff.js +51 -0
  35. package/src/components/comparisonTable.js +43 -0
  36. package/src/components/cornerAccent.js +32 -0
  37. package/src/components/dotPattern.js +30 -0
  38. package/src/components/geometricConfetti.js +34 -0
  39. package/src/components/gradientMesh.js +32 -0
  40. package/src/components/iconList.js +43 -0
  41. package/src/components/image.js +11 -0
  42. package/src/components/kanbanColumn.js +38 -0
  43. package/src/components/link.js +23 -0
  44. package/src/components/organicBlob.js +45 -0
  45. package/src/components/pricingColumn.js +53 -0
  46. package/src/components/progressBar.js +55 -0
  47. package/src/components/ratingStars.js +25 -0
  48. package/src/components/shape.js +12 -0
  49. package/src/components/slide.js +5 -0
  50. package/src/components/socialBar.js +59 -0
  51. package/src/components/squiggleLine.js +26 -0
  52. package/src/components/stepProcess.js +39 -0
  53. package/src/components/table.js +23 -0
  54. package/src/components/tagCloud.js +39 -0
  55. package/src/components/testimonialCard.js +54 -0
  56. package/src/components/text.js +14 -0
  57. package/src/components/theme.js +7 -0
  58. package/src/components/timeline.js +73 -0
  59. package/src/components/waveDecoration.js +35 -0
  60. package/src/core/PPTManager.js +17 -0
  61. package/src/index.js +225 -0
  62. package/src/layout/bento.js +47 -0
  63. package/src/layout/checkerboard.js +36 -0
  64. package/src/layout/filmStrip.js +29 -0
  65. package/src/layout/gallery.js +50 -0
  66. package/src/layout/grid.js +37 -0
  67. package/src/layout/hero.js +30 -0
  68. package/src/layout/magazine.js +39 -0
  69. package/src/layout/radial.js +34 -0
  70. package/src/layout/sidebar.js +26 -0
  71. package/src/layout/splitScreen.js +36 -0
  72. package/src/layout/zPattern.js +29 -0
  73. package/src/system/animation.js +36 -0
  74. package/src/system/contrastChecker.js +35 -0
  75. package/src/system/dataAdapter.js +36 -0
  76. package/src/system/layoutDebugger.js +40 -0
  77. package/src/system/markdownEngine.js +45 -0
  78. package/src/system/masterOverlay.js +50 -0
  79. package/src/system/sectionDivider.js +41 -0
  80. package/src/system/smartIcon.js +33 -0
  81. package/src/system/smartText.js +44 -0
  82. package/src/system/speakerNotes.js +12 -0
  83. package/src/system/syntaxHighlighter.js +71 -0
  84. package/src/system/themeGenerator.js +25 -0
  85. package/src/system/tocGenerator.js +68 -0
  86. package/src/system/watermark.js +26 -0
  87. package/src/themes/index.js +93 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Card component
3
+ * Supports any pptx.ShapeType
4
+ */
5
+
6
+ function addCard(slide, options = {}) {
7
+ const {
8
+ x,
9
+ y,
10
+ w,
11
+ h,
12
+ background = "FFFFFF",
13
+ border = "DDDDDD",
14
+ padding = 0.3,
15
+ title,
16
+ body,
17
+ theme,
18
+ shapeType, // REQUIRED
19
+ } = options;
20
+
21
+ if (!shapeType) {
22
+ throw new Error(
23
+ "addCard: shapeType is required (e.g. pptx.ShapeType.rect)"
24
+ );
25
+ }
26
+
27
+ // Card shape
28
+ slide.addShape(shapeType, {
29
+ x,
30
+ y,
31
+ w,
32
+ h,
33
+ fill: background,
34
+ line: { color: border },
35
+ rounding: shapeType === "roundRect" ? 0.15 : undefined,
36
+ });
37
+
38
+ // Title
39
+ if (title) {
40
+ slide.addText(title, {
41
+ x: x + padding,
42
+ y: y + padding,
43
+ w: w - padding * 2,
44
+ fontSize: theme?.heading?.fontSize || 16,
45
+ bold: true,
46
+ color: theme?.heading?.color || "111111",
47
+ align: "center",
48
+ });
49
+ }
50
+
51
+ // Body
52
+ if (body) {
53
+ slide.addText(body, {
54
+ x: x + padding,
55
+ y: y + padding + 0.6,
56
+ w: w - padding * 2,
57
+ fontSize: theme?.body?.fontSize || 12,
58
+ color: theme?.body?.color || "444444",
59
+ align: "center",
60
+ });
61
+ }
62
+ }
63
+
64
+ module.exports = { addCard };
@@ -0,0 +1,19 @@
1
+ function addChart(slide, chartType, data, options = {}) {
2
+ slide.addChart(chartType, data, {
3
+ x: options.x ?? 1,
4
+ y: options.y ?? 1,
5
+ w: options.w ?? 6,
6
+ h: options.h ?? 4,
7
+
8
+ title: options.title,
9
+ showLegend: options.showLegend ?? true,
10
+
11
+ // INTERACTIVITY (PowerPoint-native)
12
+ chartColors: options.colors,
13
+ animation: options.animation ?? "fade",
14
+ showValue: options.showValue ?? true,
15
+ showPercent: options.showPercent ?? false,
16
+ });
17
+ }
18
+
19
+ module.exports = { addChart };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Renders a code snippet box
3
+ */
4
+ function addCodeBlock(slide, code, options = {}) {
5
+ const {
6
+ x = 1,
7
+ y = 1,
8
+ w = 6,
9
+ h = 3,
10
+ fontSize = 11,
11
+ background = "1E1E1E", // Dark VS Code style
12
+ color = "D4D4D4",
13
+ } = options;
14
+
15
+ // Container
16
+ slide.addShape("rect", {
17
+ x,
18
+ y,
19
+ w,
20
+ h,
21
+ fill: background,
22
+ line: { color: "333333" },
23
+ });
24
+
25
+ // Code Text (Monospaced font usually requires a specific font name installed,
26
+ // but standard fonts work for general purpose)
27
+ slide.addText(code, {
28
+ x: x + 0.2,
29
+ y: y + 0.2,
30
+ w: w - 0.4,
31
+ h: h - 0.4,
32
+ fontSize: fontSize,
33
+ color: color,
34
+ fontFace: "Courier New", // Standard monospaced font
35
+ align: "left",
36
+ valign: "top",
37
+ });
38
+ }
39
+
40
+ module.exports = { addCodeBlock };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Renders a code block that highlights diffs.
3
+ * Lines starting with "+" are green.
4
+ * Lines starting with "-" are red.
5
+ */
6
+ function addCodeDiff(slide, diffText, options = {}) {
7
+ const {
8
+ x = 1, y = 1, w = 8, h = 4,
9
+ fontSize = 12,
10
+ background = "1E1E1E"
11
+ } = options;
12
+
13
+ // Background
14
+ slide.addShape("rect", { x, y, w, h, fill: background });
15
+
16
+ const lines = diffText.split("\n");
17
+ let currentY = y + 0.2;
18
+ const lineHeight = fontSize * 0.0035;
19
+
20
+ lines.forEach(line => {
21
+ let color = "D4D4D4"; // Default Grey
22
+ let bgLine = null;
23
+
24
+ if (line.startsWith("+")) {
25
+ color = "4CAF50"; // Green text
26
+ // Optional: Add faint green background strip for the line
27
+ // bgLine = "0f291e";
28
+ } else if (line.startsWith("-")) {
29
+ color = "F44336"; // Red text
30
+ // bgLine = "3e1616";
31
+ } else if (line.startsWith("@@")) {
32
+ color = "569CD6"; // Blue for chunk headers
33
+ }
34
+
35
+ // Render Text
36
+ slide.addText(line, {
37
+ x: x + 0.2,
38
+ y: currentY,
39
+ w: w - 0.4,
40
+ h: lineHeight,
41
+ fontFace: "Courier New",
42
+ fontSize: fontSize,
43
+ color: color,
44
+ align: "left"
45
+ });
46
+
47
+ currentY += 0.25;
48
+ });
49
+ }
50
+
51
+ module.exports = { addCodeDiff };
@@ -0,0 +1,43 @@
1
+ function addComparisonTable(slide, leftData, rightData, options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 8, h = 4,
4
+ leftColor = "E8F5E9", rightColor = "FFEBEE"
5
+ } = options;
6
+
7
+ const colW = w / 2;
8
+
9
+ // Backgrounds
10
+ slide.addShape("rect", { x, y, w: colW, h, fill: leftColor });
11
+ slide.addShape("rect", { x: x + colW, y, w: colW, h, fill: rightColor });
12
+
13
+ // Headers
14
+ slide.addText(leftData.title, {
15
+ x, y, w: colW, h: 0.5,
16
+ bold: true, align: "center", fontSize: 16
17
+ });
18
+ slide.addText(rightData.title, {
19
+ x: x + colW, y, w: colW, h: 0.5,
20
+ bold: true, align: "center", fontSize: 16
21
+ });
22
+
23
+ // Lists
24
+ const listOpts = { fontSize: 12, bullet: true, color: "333333" };
25
+
26
+ // Left Items
27
+ leftData.items.forEach((item, i) => {
28
+ slide.addText(item, {
29
+ x: x + 0.2, y: y + 0.6 + (i*0.4), w: colW - 0.4, h: 0.4,
30
+ ...listOpts
31
+ });
32
+ });
33
+
34
+ // Right Items
35
+ rightData.items.forEach((item, i) => {
36
+ slide.addText(item, {
37
+ x: x + colW + 0.2, y: y + 0.6 + (i*0.4), w: colW - 0.4, h: 0.4,
38
+ ...listOpts
39
+ });
40
+ });
41
+ }
42
+
43
+ module.exports = { addComparisonTable };
@@ -0,0 +1,32 @@
1
+ function addCornerAccent(slide, corner = "top-right", options = {}) {
2
+ const {
3
+ size = 2,
4
+ color = "FFC107" // Amber
5
+ } = options;
6
+
7
+ let x, y, rotate;
8
+ const slideW = 10; // Default width
9
+ const slideH = 5.63; // Default height
10
+
11
+ switch (corner) {
12
+ case "top-left": x = -size/2; y = -size/2; rotate = 180; break;
13
+ case "bottom-left": x = -size/2; y = slideH - size/2; rotate = 270; break;
14
+ case "bottom-right": x = slideW - size/2; y = slideH - size/2; rotate = 0; break;
15
+ case "top-right": default: x = slideW - size/2; y = -size/2; rotate = 90; break;
16
+ }
17
+
18
+ // A quarter circle (arc) or a triangle in the corner.
19
+ // Using a rotated Triangle is very modern.
20
+
21
+ slide.addShape("rtTriangle", { // Right Triangle
22
+ x: x,
23
+ y: y,
24
+ w: size,
25
+ h: size,
26
+ fill: color,
27
+ rotate: rotate,
28
+ line: { color: undefined }
29
+ });
30
+ }
31
+
32
+ module.exports = { addCornerAccent };
@@ -0,0 +1,30 @@
1
+ function addDotPattern(slide, options = {}) {
2
+ const {
3
+ x = 1,
4
+ y = 1,
5
+ w = 3,
6
+ h = 3,
7
+ color = "CCCCCC",
8
+ rows = 6,
9
+ cols = 6,
10
+ size = 0.05
11
+ } = options;
12
+
13
+ const gapX = (w - size) / (cols - 1);
14
+ const gapY = (h - size) / (rows - 1);
15
+
16
+ for (let r = 0; r < rows; r++) {
17
+ for (let c = 0; c < cols; c++) {
18
+ slide.addShape("oval", {
19
+ x: x + c * gapX,
20
+ y: y + r * gapY,
21
+ w: size,
22
+ h: size,
23
+ fill: color,
24
+ line: { color: undefined }
25
+ });
26
+ }
27
+ }
28
+ }
29
+
30
+ module.exports = { addDotPattern };
@@ -0,0 +1,34 @@
1
+ function addGeometricConfetti(slide, options = {}) {
2
+ const {
3
+ x = 0,
4
+ y = 0,
5
+ w = 10,
6
+ h = 5.63,
7
+ count = 10,
8
+ colors = ["FF5722", "00BCD4", "FFC107"]
9
+ } = options;
10
+
11
+ const shapes = ["triangle", "oval", "rect", "cross"];
12
+
13
+ for (let i = 0; i < count; i++) {
14
+ // Random positions within the bounding box
15
+ const randX = x + Math.random() * w;
16
+ const randY = y + Math.random() * h;
17
+ const randSize = 0.1 + Math.random() * 0.2; // Small size
18
+ const randShape = shapes[Math.floor(Math.random() * shapes.length)];
19
+ const randColor = colors[Math.floor(Math.random() * colors.length)];
20
+ const randRot = Math.random() * 360;
21
+
22
+ slide.addShape(randShape, {
23
+ x: randX,
24
+ y: randY,
25
+ w: randSize,
26
+ h: randSize,
27
+ fill: randColor,
28
+ rotate: randRot,
29
+ line: { color: undefined }
30
+ });
31
+ }
32
+ }
33
+
34
+ module.exports = { addGeometricConfetti };
@@ -0,0 +1,32 @@
1
+ function addGradientMesh(slide, options = {}) {
2
+ const {
3
+ x = 0,
4
+ y = 0,
5
+ w = 5,
6
+ h = 5,
7
+ color = "007AFF",
8
+ opacity = 50
9
+ } = options;
10
+
11
+ // PowerPoint JS libraries often handle gradients via specific fill objects.
12
+ // We simulate a mesh glow using a radial gradient if supported,
13
+ // or a highly transparent soft circle.
14
+
15
+ slide.addShape("oval", {
16
+ x: x,
17
+ y: y,
18
+ w: w,
19
+ h: h,
20
+ fill: {
21
+ type: "gradient",
22
+ gradientType: "radial",
23
+ stops: [
24
+ { position: 0, color: color, alpha: (100-opacity)/100 }, // Center
25
+ { position: 1, color: "FFFFFF", alpha: 0 } // Edge (fade out)
26
+ ]
27
+ },
28
+ line: { color: undefined }
29
+ });
30
+ }
31
+
32
+ module.exports = { addGradientMesh };
@@ -0,0 +1,43 @@
1
+ function addIconList(slide, items = [], options = {}) {
2
+ const {
3
+ x = 1,
4
+ y = 1,
5
+ w = 5,
6
+ itemHeight = 0.5,
7
+ gap = 0.1,
8
+ iconColor = "007AFF",
9
+ textColor = "333333"
10
+ } = options;
11
+
12
+ items.forEach((text, i) => {
13
+ const curY = y + i * (itemHeight + gap);
14
+
15
+ // Icon (Checkmark style shape)
16
+ slide.addShape("oval", {
17
+ x: x,
18
+ y: curY + 0.1,
19
+ w: 0.25,
20
+ h: 0.25,
21
+ fill: iconColor
22
+ });
23
+
24
+ // Checkmark inside
25
+ slide.addText("✓", {
26
+ x: x, y: curY + 0.1, w: 0.25, h: 0.25,
27
+ color: "FFFFFF", fontSize: 10, align: "center", valign: "middle"
28
+ });
29
+
30
+ // Text
31
+ slide.addText(text, {
32
+ x: x + 0.4,
33
+ y: curY,
34
+ w: w - 0.4,
35
+ h: itemHeight,
36
+ fontSize: 14,
37
+ color: textColor,
38
+ valign: "middle"
39
+ });
40
+ });
41
+ }
42
+
43
+ module.exports = { addIconList };
@@ -0,0 +1,11 @@
1
+ function addImage(slide, imagePath, options = {}) {
2
+ slide.addImage({
3
+ path: imagePath,
4
+ x: options.x ?? 1,
5
+ y: options.y ?? 1,
6
+ w: options.w ?? 3,
7
+ h: options.h ?? 3,
8
+ });
9
+ }
10
+
11
+ module.exports = { addImage };
@@ -0,0 +1,38 @@
1
+ function addKanbanColumn(slide, title, cards = [], options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 3, h = 5,
4
+ bgColor = "F4F5F7"
5
+ } = options;
6
+
7
+ // Background
8
+ slide.addShape("rect", {
9
+ x, y, w, h,
10
+ fill: bgColor,
11
+ rounding: 0.1 // slight rounded corners for column
12
+ });
13
+
14
+ // Title
15
+ slide.addText(title, {
16
+ x: x + 0.1, y: y + 0.1, w: w - 0.2, h: 0.4,
17
+ bold: true, fontSize: 12, color: "172B4D"
18
+ });
19
+
20
+ // Cards
21
+ let cardY = y + 0.6;
22
+ cards.forEach(cardText => {
23
+ slide.addShape("rect", {
24
+ x: x + 0.1, y: cardY, w: w - 0.2, h: 0.8,
25
+ fill: "FFFFFF",
26
+ line: { color: "DFE1E6" } // Border
27
+ });
28
+
29
+ slide.addText(cardText, {
30
+ x: x + 0.2, y: cardY, w: w - 0.4, h: 0.8,
31
+ fontSize: 10, color: "333333", valign: "middle"
32
+ });
33
+
34
+ cardY += 0.9;
35
+ });
36
+ }
37
+
38
+ module.exports = { addKanbanColumn };
@@ -0,0 +1,23 @@
1
+ function addLink(slide, text, url, options = {}) {
2
+ slide.addText(
3
+ [
4
+ {
5
+ text,
6
+ options: {
7
+ hyperlink: { url },
8
+ color: "0000FF",
9
+ underline: true,
10
+ },
11
+ },
12
+ ],
13
+ {
14
+ x: options.x ?? 1,
15
+ y: options.y ?? 1,
16
+ w: options.w ?? 4,
17
+ h: options.h ?? 1,
18
+ fontSize: options.fontSize ?? 14,
19
+ }
20
+ );
21
+ }
22
+
23
+ module.exports = { addLink };
@@ -0,0 +1,45 @@
1
+ function addOrganicBlob(slide, options = {}) {
2
+ const {
3
+ x = 1,
4
+ y = 1,
5
+ w = 4,
6
+ h = 4,
7
+ color = "F0F4FF", // Very light blue
8
+ opacity = 100 // 0-100 (pptxgenjs usually handles transparency via alpha or hex)
9
+ } = options;
10
+
11
+ // To simulate a "blob", we create a cluster of 3 rotated ovals
12
+ // anchored around the center point.
13
+
14
+ // Blob Part 1 (Main body)
15
+ slide.addShape("oval", {
16
+ x: x,
17
+ y: y,
18
+ w: w,
19
+ h: h * 0.8,
20
+ fill: { color: color, transparency: 100 - opacity },
21
+ line: { color: undefined } // No border
22
+ });
23
+
24
+ // Blob Part 2 (rotated stretch)
25
+ slide.addShape("oval", {
26
+ x: x - w * 0.1,
27
+ y: y + h * 0.1,
28
+ w: w * 0.9,
29
+ h: h * 0.9,
30
+ rotate: 45,
31
+ fill: { color: color, transparency: 100 - opacity }
32
+ });
33
+
34
+ // Blob Part 3 (smoothing clump)
35
+ slide.addShape("oval", {
36
+ x: x + w * 0.2,
37
+ y: y - h * 0.1,
38
+ w: w * 0.7,
39
+ h: h * 0.7,
40
+ rotate: -30,
41
+ fill: { color: color, transparency: 100 - opacity }
42
+ });
43
+ }
44
+
45
+ module.exports = { addOrganicBlob };
@@ -0,0 +1,53 @@
1
+ function addPricingColumn(slide, plan, options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 2.5, h = 4,
4
+ headerColor = "333333",
5
+ priceColor = "007AFF"
6
+ } = options;
7
+
8
+ // Container Border
9
+ slide.addShape("rect", {
10
+ x, y, w, h,
11
+ line: { color: "DDDDDD" },
12
+ fill: "FFFFFF"
13
+ });
14
+
15
+ // Header
16
+ slide.addShape("rect", {
17
+ x, y, w, h: 0.8,
18
+ fill: headerColor
19
+ });
20
+ slide.addText(plan.name, {
21
+ x, y, w, h: 0.8,
22
+ color: "FFFFFF", bold: true, align: "center", valign: "middle", fontSize: 14
23
+ });
24
+
25
+ // Price
26
+ slide.addText(plan.price, {
27
+ x, y: y + 0.9, w, h: 0.6,
28
+ color: priceColor, bold: true, align: "center", fontSize: 24
29
+ });
30
+
31
+ // Features
32
+ const startY = y + 1.6;
33
+ if (plan.features) {
34
+ plan.features.forEach((feat, i) => {
35
+ slide.addText(feat, {
36
+ x: x + 0.2, y: startY + (i * 0.4), w: w - 0.4, h: 0.4,
37
+ fontSize: 10, align: "center", color: "666666"
38
+ });
39
+ });
40
+ }
41
+
42
+ // Button Visual
43
+ slide.addShape("roundRect", {
44
+ x: x + 0.4, y: y + h - 0.7, w: w - 0.8, h: 0.4,
45
+ fill: priceColor, rounding: 0.5
46
+ });
47
+ slide.addText("Select", {
48
+ x: x + 0.4, y: y + h - 0.7, w: w - 0.8, h: 0.4,
49
+ color: "FFFFFF", fontSize: 10, bold: true, align: "center", valign: "middle"
50
+ });
51
+ }
52
+
53
+ module.exports = { addPricingColumn };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Renders a progress bar (track + fill)
3
+ */
4
+ function addProgressBar(slide, options = {}) {
5
+ const {
6
+ x = 1,
7
+ y = 1,
8
+ w = 5,
9
+ h = 0.3,
10
+ percent = 0.5, // 0.0 to 1.0
11
+ color = "007AFF",
12
+ trackColor = "E5E5EA",
13
+ showLabel = true,
14
+ } = options;
15
+
16
+ // 1. Draw Track (Background)
17
+ slide.addShape("rect", {
18
+ x,
19
+ y,
20
+ w,
21
+ h,
22
+ fill: trackColor,
23
+ line: { color: trackColor },
24
+ rounding: h / 2, // Pill shape
25
+ });
26
+
27
+ // 2. Draw Fill (Foreground)
28
+ if (percent > 0) {
29
+ slide.addShape("rect", {
30
+ x,
31
+ y,
32
+ w: w * percent,
33
+ h,
34
+ fill: color,
35
+ line: { color: color }, // Hide border
36
+ rounding: h / 2,
37
+ });
38
+ }
39
+
40
+ // 3. Optional Label (e.g., "50%")
41
+ if (showLabel) {
42
+ slide.addText(`${Math.round(percent * 100)}%`, {
43
+ x: x + w + 0.1,
44
+ y: y,
45
+ w: 1,
46
+ h: h,
47
+ fontSize: 10,
48
+ color: "666666",
49
+ align: "left",
50
+ valign: "middle",
51
+ });
52
+ }
53
+ }
54
+
55
+ module.exports = { addProgressBar };
@@ -0,0 +1,25 @@
1
+ function addRatingStars(slide, rating = 0, options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 2, h = 0.4,
4
+ max = 5,
5
+ fillColor = "FFD700", // Gold
6
+ emptyColor = "E0E0E0"
7
+ } = options;
8
+
9
+ const starSize = h;
10
+ const gap = 0.1;
11
+
12
+ for (let i = 1; i <= max; i++) {
13
+ const isFilled = i <= rating;
14
+ const curX = x + (i - 1) * (starSize + gap);
15
+
16
+ // Using text "★" is safer than shapes for compatibility
17
+ slide.addText("★", {
18
+ x: curX, y, w: starSize, h: starSize,
19
+ color: isFilled ? fillColor : emptyColor,
20
+ fontSize: starSize * 40 // approximate scaling
21
+ });
22
+ }
23
+ }
24
+
25
+ module.exports = { addRatingStars };
@@ -0,0 +1,12 @@
1
+ function addShape(slide, shapeType, options = {}) {
2
+ slide.addShape(shapeType, {
3
+ x: options.x ?? 1,
4
+ y: options.y ?? 1,
5
+ w: options.w ?? 2,
6
+ h: options.h ?? 2,
7
+ fill: options.fill ?? "FFFFFF",
8
+ line: options.line ?? { color: "000000" },
9
+ });
10
+ }
11
+
12
+ module.exports = { addShape };
@@ -0,0 +1,5 @@
1
+ function addSlide(pptx, options = {}) {
2
+ return pptx.addSlide(options);
3
+ }
4
+
5
+ module.exports = { addSlide };