@taloswork/ose-shared 0.1.2 → 0.1.3

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 (138) hide show
  1. package/package.json +3 -3
  2. package/skills/document/SKILL.md +29 -33
  3. package/skills/document/assets/fonts/Archivo-Regular.woff2 +0 -0
  4. package/skills/document/assets/fonts/Archivo-SemiBold.woff2 +0 -0
  5. package/skills/document/assets/fonts/BigShouldersDisplay-Bold.woff2 +0 -0
  6. package/skills/document/assets/fonts/BodoniModa-SemiBold.woff2 +0 -0
  7. package/skills/document/assets/fonts/CormorantGaramond-SemiBold.woff2 +0 -0
  8. package/skills/document/assets/fonts/Fraunces-SemiBold.woff2 +0 -0
  9. package/skills/document/assets/fonts/GochiHand-Regular.woff2 +0 -0
  10. package/skills/document/assets/fonts/IBMPlexSans-Regular.woff2 +0 -0
  11. package/skills/document/assets/fonts/IBMPlexSans-SemiBold.woff2 +0 -0
  12. package/skills/document/assets/fonts/Inter-Regular.woff2 +0 -0
  13. package/skills/document/assets/fonts/Jost-Regular.woff2 +0 -0
  14. package/skills/document/assets/fonts/Jost-SemiBold.woff2 +0 -0
  15. package/skills/document/assets/fonts/Karla-Regular.woff2 +0 -0
  16. package/skills/document/assets/fonts/Lora-Regular.woff2 +0 -0
  17. package/skills/document/assets/fonts/Manrope-Bold.woff2 +0 -0
  18. package/skills/document/assets/fonts/Manrope-Regular.woff2 +0 -0
  19. package/skills/document/assets/fonts/Marcellus-Regular.woff2 +0 -0
  20. package/skills/document/assets/fonts/PublicSans-Regular.woff2 +0 -0
  21. package/skills/document/assets/fonts/Sora-Regular.woff2 +0 -0
  22. package/skills/document/assets/fonts/Sora-SemiBold.woff2 +0 -0
  23. package/skills/document/assets/fonts/fonts.json +218 -0
  24. package/skills/document/bin/deck-build.cjs +273 -5
  25. package/skills/document/bin/doc-gen.cjs +108 -23
  26. package/skills/document/bin/html2pptx.cjs +280 -49
  27. package/skills/document/catalog.json +25 -0
  28. package/skills/document/deck-design.md +191 -0
  29. package/skills/document/layouts/README.md +32 -0
  30. package/skills/document/layouts/banner-columns.tpl +9 -9
  31. package/skills/document/layouts/bento.tpl +3 -3
  32. package/skills/document/layouts/big-stat.tpl +3 -3
  33. package/skills/document/layouts/blocks-2x2.tpl +12 -12
  34. package/skills/document/layouts/brand-values.tpl +5 -5
  35. package/skills/document/layouts/cards-3.tpl +3 -3
  36. package/skills/document/layouts/cards-grid.tpl +3 -3
  37. package/skills/document/layouts/chart-full.tpl +3 -3
  38. package/skills/document/layouts/chart-kpi.tpl +3 -3
  39. package/skills/document/layouts/color-palette.tpl +5 -5
  40. package/skills/document/layouts/comparison.tpl +3 -3
  41. package/skills/document/layouts/concept-hub.tpl +3 -3
  42. package/skills/document/layouts/cover-centered.tpl +1 -1
  43. package/skills/document/layouts/cover-image.tpl +1 -1
  44. package/skills/document/layouts/cover-minimal.tpl +3 -3
  45. package/skills/document/layouts/cover-statement.tpl +3 -3
  46. package/skills/document/layouts/cover.tpl +1 -1
  47. package/skills/document/layouts/data-table.tpl +3 -3
  48. package/skills/document/layouts/dos-donts.tpl +14 -14
  49. package/skills/document/layouts/editorial-panel.tpl +11 -11
  50. package/skills/document/layouts/ending-contact.tpl +1 -1
  51. package/skills/document/layouts/ending.tpl +1 -1
  52. package/skills/document/layouts/funnel.tpl +3 -3
  53. package/skills/document/layouts/gantt.tpl +3 -3
  54. package/skills/document/layouts/hero.tpl +3 -3
  55. package/skills/document/layouts/icon-row.tpl +3 -3
  56. package/skills/document/layouts/image-full.tpl +5 -5
  57. package/skills/document/layouts/image-grid.tpl +3 -3
  58. package/skills/document/layouts/image-left.tpl +3 -3
  59. package/skills/document/layouts/list.tpl +3 -3
  60. package/skills/document/layouts/logo-guidelines.tpl +8 -8
  61. package/skills/document/layouts/map-distribution.tpl +3 -3
  62. package/skills/document/layouts/map-quad.tpl +6 -6
  63. package/skills/document/layouts/matrix-2x2.tpl +3 -3
  64. package/skills/document/layouts/numbered-brief.tpl +12 -12
  65. package/skills/document/layouts/org-tree.tpl +3 -3
  66. package/skills/document/layouts/problem-solution-banner.tpl +7 -7
  67. package/skills/document/layouts/problem-solution.tpl +3 -3
  68. package/skills/document/layouts/pyramid.tpl +3 -3
  69. package/skills/document/layouts/quote.tpl +1 -1
  70. package/skills/document/layouts/radar.tpl +3 -3
  71. package/skills/document/layouts/ring-progress.tpl +3 -3
  72. package/skills/document/layouts/section-fullbleed.tpl +3 -3
  73. package/skills/document/layouts/section-image.tpl +1 -1
  74. package/skills/document/layouts/section-stat.tpl +1 -1
  75. package/skills/document/layouts/section.tpl +1 -1
  76. package/skills/document/layouts/slots.json +1 -1
  77. package/skills/document/layouts/split-two-col.tpl +3 -3
  78. package/skills/document/layouts/stats-chart.tpl +3 -3
  79. package/skills/document/layouts/steps-serpentine.tpl +11 -11
  80. package/skills/document/layouts/steps-vertical.tpl +3 -3
  81. package/skills/document/layouts/steps.tpl +3 -3
  82. package/skills/document/layouts/team-row.tpl +4 -4
  83. package/skills/document/layouts/three-kpi.tpl +3 -3
  84. package/skills/document/layouts/timeline.tpl +3 -3
  85. package/skills/document/layouts/title-meta.tpl +5 -5
  86. package/skills/document/layouts/title.tpl +2 -2
  87. package/skills/document/layouts/toc-agenda.tpl +3 -3
  88. package/skills/document/layouts/toc-editorial.tpl +15 -0
  89. package/skills/document/layouts/toc-panel.tpl +4 -4
  90. package/skills/document/layouts/toc.tpl +3 -3
  91. package/skills/document/layouts/transition.tpl +1 -1
  92. package/skills/document/layouts/two-kpi.tpl +3 -3
  93. package/skills/document/layouts/type-specimen.tpl +10 -10
  94. package/skills/document/layouts/versus.tpl +3 -3
  95. package/skills/document/motion/README.md +11 -0
  96. package/skills/document/packs/README.md +9 -0
  97. package/skills/document/styles/README.md +36 -15
  98. package/skills/document/styles/_contract-defaults.css +55 -0
  99. package/skills/document/styles/_samples/_groups/biz-premium.webp +0 -0
  100. package/skills/document/styles/_samples/_groups/creative.webp +0 -0
  101. package/skills/document/styles/_samples/_groups/editorial.webp +0 -0
  102. package/skills/document/styles/_samples/_groups/minimal.webp +0 -0
  103. package/skills/document/styles/_samples/_groups/natural.webp +0 -0
  104. package/skills/document/styles/_samples/_groups/tech-future.webp +0 -0
  105. package/skills/document/styles/_samples/anthropic.webp +0 -0
  106. package/skills/document/styles/_samples/apple.webp +0 -0
  107. package/skills/document/styles/_samples/black-gold.webp +0 -0
  108. package/skills/document/styles/_samples/branding.webp +0 -0
  109. package/skills/document/styles/_samples/cinereel.webp +0 -0
  110. package/skills/document/styles/_samples/cool.webp +0 -0
  111. package/skills/document/styles/_samples/hand-drawn.webp +0 -0
  112. package/skills/document/styles/_samples/ivory-gold.webp +0 -0
  113. package/skills/document/styles/_samples/magazine-ink.webp +0 -0
  114. package/skills/document/styles/_samples/mckinsey.webp +0 -0
  115. package/skills/document/styles/_samples/mono.webp +0 -0
  116. package/skills/document/styles/_samples/olive-gold.webp +0 -0
  117. package/skills/document/styles/_samples/swiss-grid.webp +0 -0
  118. package/skills/document/styles/anthropic/backdrop.html +4 -0
  119. package/skills/document/styles/anthropic/skin.css +15 -8
  120. package/skills/document/styles/apple/backdrop.html +4 -1
  121. package/skills/document/styles/apple/skin.css +5 -2
  122. package/skills/document/styles/black-gold/backdrop.html +3 -0
  123. package/skills/document/styles/black-gold/skin.css +15 -8
  124. package/skills/document/styles/branding/backdrop.html +4 -0
  125. package/skills/document/styles/branding/skin.css +14 -7
  126. package/skills/document/styles/cinereel/skin.css +28 -10
  127. package/skills/document/styles/cool/backdrop.html +3 -0
  128. package/skills/document/styles/cool/skin.css +5 -2
  129. package/skills/document/styles/hand-drawn/skin.css +14 -6
  130. package/skills/document/styles/ivory-gold/skin.css +19 -6
  131. package/skills/document/styles/magazine-ink/skin.css +6 -1
  132. package/skills/document/styles/mckinsey/backdrop.html +5 -0
  133. package/skills/document/styles/mckinsey/skin.css +5 -2
  134. package/skills/document/styles/mono/backdrop.html +6 -0
  135. package/skills/document/styles/mono/skin.css +5 -2
  136. package/skills/document/styles/olive-gold/backdrop.html +5 -0
  137. package/skills/document/styles/olive-gold/skin.css +15 -8
  138. package/skills/document/styles/swiss-grid/skin.css +6 -1
@@ -287,6 +287,214 @@ function assembleDeck(spec, readLayout) {
287
287
  return { html: sections.join("\n"), warnings: problems.warnings, errors: problems.errors };
288
288
  }
289
289
 
290
+ // packages/core/dist/document/deck-catalog.js
291
+ var KINDS = ["skin", "pack"];
292
+ var MODES = ["light", "dark"];
293
+ var ID_RE = /^[a-z0-9][a-z0-9-]*$/;
294
+ function isStr(v) {
295
+ return typeof v === "string" && v.length > 0;
296
+ }
297
+ function isStrArr(v) {
298
+ return Array.isArray(v) && v.every((x) => typeof x === "string");
299
+ }
300
+ function parseCatalog(raw) {
301
+ const errors = [];
302
+ const o = raw;
303
+ if (!o || typeof o !== "object")
304
+ return { catalog: null, errors: ["catalog is not an object"] };
305
+ const groups = [];
306
+ const rawGroups = Array.isArray(o.groups) ? o.groups : [];
307
+ if (!Array.isArray(o.groups))
308
+ errors.push("catalog.groups must be an array");
309
+ rawGroups.forEach((g, i) => {
310
+ const at = `group[${i}]`;
311
+ if (!isStr(g?.id) || !ID_RE.test(g.id))
312
+ errors.push(`${at}: bad id`);
313
+ if (!isStr(g?.name_cn))
314
+ errors.push(`${at}: missing name_cn`);
315
+ if (!isStr(g?.sample))
316
+ errors.push(`${at}: missing sample`);
317
+ if (!isStrArr(g?.scenarios))
318
+ errors.push(`${at}: scenarios must be a string array`);
319
+ if (isStr(g?.id) && isStr(g?.name_cn) && isStr(g?.sample) && isStrArr(g?.scenarios)) {
320
+ groups.push({ id: g.id, name_cn: g.name_cn, sample: g.sample, scenarios: g.scenarios });
321
+ }
322
+ });
323
+ const entries = [];
324
+ const rawEntries = Array.isArray(o.entries) ? o.entries : [];
325
+ if (!Array.isArray(o.entries))
326
+ errors.push("catalog.entries must be an array");
327
+ rawEntries.forEach((e, i) => {
328
+ const at = `entry[${i}]${isStr(e?.id) ? ` (${e.id})` : ""}`;
329
+ const before = errors.length;
330
+ if (!isStr(e?.id) || !ID_RE.test(e.id))
331
+ errors.push(`${at}: bad id`);
332
+ if (!isStr(e?.kind) || !KINDS.includes(e.kind))
333
+ errors.push(`${at}: kind must be "skin" or "pack"`);
334
+ if (!isStr(e?.group))
335
+ errors.push(`${at}: missing group`);
336
+ if (!isStr(e?.name_cn))
337
+ errors.push(`${at}: missing name_cn`);
338
+ if (!isStr(e?.oneliner))
339
+ errors.push(`${at}: missing oneliner`);
340
+ if (!isStrArr(e?.scenarios))
341
+ errors.push(`${at}: scenarios must be a string array`);
342
+ if (!isStr(e?.mode) || !MODES.includes(e.mode))
343
+ errors.push(`${at}: mode must be "light" or "dark"`);
344
+ if (!isStr(e?.sample))
345
+ errors.push(`${at}: missing sample`);
346
+ if (e?.motion !== void 0 && !isStr(e.motion))
347
+ errors.push(`${at}: motion must be a string when present`);
348
+ if (errors.length === before) {
349
+ entries.push({
350
+ id: e.id,
351
+ kind: e.kind,
352
+ group: e.group,
353
+ name_cn: e.name_cn,
354
+ oneliner: e.oneliner,
355
+ scenarios: e.scenarios,
356
+ mode: e.mode,
357
+ sample: e.sample,
358
+ ...e.motion !== void 0 ? { motion: e.motion } : {}
359
+ });
360
+ }
361
+ });
362
+ return { catalog: errors.length ? null : { groups, entries }, errors };
363
+ }
364
+ function resolveEntry(catalog, id) {
365
+ return catalog.entries.find((e) => e.id === id) ?? null;
366
+ }
367
+
368
+ // packages/core/dist/document/deck-motion.js
369
+ var ANIM_EFFECTS = [
370
+ "fade",
371
+ "fade-up",
372
+ "float",
373
+ "appear",
374
+ "fly-up",
375
+ "fly-down",
376
+ "fly-left",
377
+ "fly-right"
378
+ ];
379
+ var START_MODES = ["after", "with", "onclick"];
380
+ var SEL_RE = /^\.[a-z][a-z0-9-]*$/;
381
+ function validateMotionPreset(raw) {
382
+ const errors = [];
383
+ const p = raw;
384
+ if (!p || typeof p !== "object")
385
+ return ["motion preset is not an object"];
386
+ if (p.transition !== void 0) {
387
+ const t = p.transition;
388
+ if (!t || typeof t.effect !== "string" || !t.effect)
389
+ errors.push("transition.effect must be a non-empty string");
390
+ if (t?.durMs !== void 0 && typeof t.durMs !== "number")
391
+ errors.push("transition.durMs must be a number");
392
+ if (t?.dir !== void 0 && typeof t.dir !== "string")
393
+ errors.push("transition.dir must be a string");
394
+ }
395
+ if (p.entrance !== void 0) {
396
+ if (typeof p.entrance !== "object" || p.entrance === null) {
397
+ errors.push("entrance must be an object keyed by role");
398
+ } else {
399
+ for (const [role, steps] of Object.entries(p.entrance)) {
400
+ if (!Array.isArray(steps)) {
401
+ errors.push(`entrance.${role} must be an array`);
402
+ continue;
403
+ }
404
+ steps.forEach((s, i) => {
405
+ const at = `entrance.${role}[${i}]`;
406
+ if (typeof s?.sel !== "string" || !SEL_RE.test(s.sel))
407
+ errors.push(`${at}: sel must be a single class selector like ".card"`);
408
+ if (typeof s?.anim !== "string" || !ANIM_EFFECTS.includes(s.anim)) {
409
+ errors.push(`${at}: anim "${String(s?.anim)}" is not implemented by pptx-anim.ts`);
410
+ }
411
+ for (const k of ["delay", "dur", "stagger"]) {
412
+ if (s?.[k] !== void 0 && typeof s[k] !== "number")
413
+ errors.push(`${at}: ${k} must be a number`);
414
+ }
415
+ if (s?.start !== void 0 && !START_MODES.includes(s.start))
416
+ errors.push(`${at}: start must be one of ${START_MODES.join("/")}`);
417
+ });
418
+ }
419
+ }
420
+ }
421
+ return errors;
422
+ }
423
+ var ROLE_OVERRIDES = {
424
+ transition: "section",
425
+ hero: "cover",
426
+ title: "cover",
427
+ "title-meta": "cover",
428
+ quote: "content",
429
+ bento: "cards",
430
+ list: "cards",
431
+ "icon-row": "cards",
432
+ "cards-grid": "cards",
433
+ "blocks-2x2": "cards",
434
+ "chart-kpi": "stat",
435
+ "two-kpi": "stat",
436
+ "three-kpi": "stat",
437
+ "big-stat": "stat",
438
+ "stats-chart": "stat"
439
+ };
440
+ function roleOfLayout(layoutId) {
441
+ if (ROLE_OVERRIDES[layoutId])
442
+ return ROLE_OVERRIDES[layoutId];
443
+ if (layoutId.startsWith("cover"))
444
+ return "cover";
445
+ if (layoutId.startsWith("toc"))
446
+ return "toc";
447
+ if (layoutId.startsWith("section"))
448
+ return "section";
449
+ if (layoutId.startsWith("ending"))
450
+ return "ending";
451
+ if (layoutId.startsWith("cards"))
452
+ return "cards";
453
+ return "content";
454
+ }
455
+ var num2 = (v) => typeof v === "number" && Number.isFinite(v) ? String(Math.round(v)) : null;
456
+ function addAttrs(tag, attrs) {
457
+ if (/\bdata-anim=/.test(tag))
458
+ return tag;
459
+ const extra = Object.entries(attrs).filter(([, v]) => v !== null).map(([k, v]) => ` ${k}="${v}"`).join("");
460
+ return tag.replace(/\s*\/?>$/, (end) => extra + end);
461
+ }
462
+ function applyMotion(html, layoutId, preset) {
463
+ let out = html;
464
+ const role = roleOfLayout(layoutId);
465
+ const steps = preset.entrance?.[role];
466
+ if (steps?.length) {
467
+ let seq = 0;
468
+ for (const step of steps) {
469
+ const cls = step.sel.slice(1);
470
+ const re = new RegExp(`<([a-z][a-z0-9]*)\\b([^>]*\\bclass="[^"]*(?<![\\w-])${cls}(?![\\w-])[^"]*"[^>]*)>`, "gi");
471
+ let nth = 0;
472
+ out = out.replace(re, (tag) => {
473
+ nth += 1;
474
+ seq += 1;
475
+ const delay = nth === 1 ? num2(step.delay) : num2(step.stagger ?? step.delay);
476
+ return addAttrs(tag, {
477
+ "data-anim": step.anim,
478
+ "data-anim-seq": String(seq),
479
+ "data-anim-delay": delay,
480
+ "data-anim-dur": num2(step.dur),
481
+ "data-anim-start": step.start ?? null
482
+ });
483
+ });
484
+ }
485
+ }
486
+ const t = preset.transition;
487
+ if (t?.effect) {
488
+ out = out.replace(/<section\b([^>]*\bclass="[^"]*(?<![\w-])slide(?![\w-])[^"]*"[^>]*)>/i, (tag) => {
489
+ if (/\bdata-transition=/.test(tag))
490
+ return tag;
491
+ const extra = ` data-transition="${t.effect}"` + (t.dir ? ` data-transition-dir="${t.dir}"` : "") + (num2(t.durMs) ? ` data-transition-dur="${num2(t.durMs)}"` : "");
492
+ return tag.replace(/\s*>$/, extra + ">");
493
+ });
494
+ }
495
+ return out;
496
+ }
497
+
290
498
  // apps/admin/data/skills.lib/document/bin-src/deck-build.mjs
291
499
  function die(msg, code = 1) {
292
500
  process.stderr.write(`deck-build: ${msg}
@@ -303,11 +511,36 @@ async function main() {
303
511
  } catch (e) {
304
512
  die(`cannot read spec ${specPath}: ${e.message}`, 66);
305
513
  }
306
- const layoutsDir = (0, import_node_path.join)((0, import_node_path.dirname)((0, import_node_path.dirname)(process.argv[1] || "")), "layouts");
514
+ const skillDir = (0, import_node_path.dirname)((0, import_node_path.dirname)(process.argv[1] || ""));
515
+ const layoutsDir = (0, import_node_path.join)(skillDir, "layouts");
516
+ let catalogEntry = null;
517
+ let packLayoutsDir = null;
518
+ const styleId = typeof spec?.style === "string" ? spec.style : null;
519
+ if (styleId) {
520
+ const catalogPath = (0, import_node_path.join)(skillDir, "catalog.json");
521
+ if ((0, import_node_fs.existsSync)(catalogPath)) {
522
+ try {
523
+ const { catalog } = parseCatalog(JSON.parse((0, import_node_fs.readFileSync)(catalogPath, "utf8")));
524
+ catalogEntry = catalog ? resolveEntry(catalog, styleId) : null;
525
+ if (catalogEntry?.kind === "pack") packLayoutsDir = (0, import_node_path.join)(skillDir, "packs", catalogEntry.id, "layouts");
526
+ } catch {
527
+ }
528
+ }
529
+ }
530
+ let fromPack = 0, fromShared = 0;
307
531
  const readLayout = (id) => {
308
532
  if (!/^[a-z0-9-]+$/i.test(id)) return null;
533
+ if (packLayoutsDir) {
534
+ const pp = (0, import_node_path.join)(packLayoutsDir, `${id}.tpl`);
535
+ if ((0, import_node_fs.existsSync)(pp)) {
536
+ fromPack++;
537
+ return (0, import_node_fs.readFileSync)(pp, "utf8");
538
+ }
539
+ }
309
540
  const p = (0, import_node_path.join)(layoutsDir, `${id}.tpl`);
310
- return (0, import_node_fs.existsSync)(p) ? (0, import_node_fs.readFileSync)(p, "utf8") : null;
541
+ if (!(0, import_node_fs.existsSync)(p)) return null;
542
+ if (packLayoutsDir) fromShared++;
543
+ return (0, import_node_fs.readFileSync)(p, "utf8");
311
544
  };
312
545
  const { html, warnings, errors } = assembleDeck(spec, readLayout);
313
546
  for (const w of warnings) process.stderr.write(`deck-build: ${w}
@@ -317,14 +550,49 @@ async function main() {
317
550
  `);
318
551
  die(`${errors.length} spec error(s) \u2014 nothing written (see layouts/slots.json for each layout's slots + rows)`, 1);
319
552
  }
320
- await (0, import_promises.writeFile)(outPath, html, "utf8");
321
- const style = typeof spec?.style === "string" ? spec.style : null;
553
+ const resolved = fromPack + fromShared;
554
+ if (packLayoutsDir && resolved > 0) {
555
+ const ratio = fromShared / resolved;
556
+ if (ratio > 0.4) {
557
+ process.stderr.write(
558
+ `deck-build: pack-dilution \u2014 ${fromShared}/${resolved} \u9875\uFF08${Math.round(ratio * 100)}%\uFF09\u56DE\u843D\u5230\u5171\u4EAB\u7248\u5F0F\uFF0C\u8D85\u8FC7 40% \u9608\u503C\u3002\u5305 "${styleId}" \u7684\u9875\u9762\u6E05\u5355\u76F8\u5BF9\u672C\u6B21\u5185\u5BB9\u91CF\u504F\u8584\uFF0C\u8003\u8651\u6269\u5305\u6216\u6539\u7528 skin\u3002
559
+ `
560
+ );
561
+ }
562
+ }
563
+ let motionPreset = null;
564
+ if (catalogEntry?.motion) {
565
+ const mp = (0, import_node_path.join)(skillDir, catalogEntry.motion);
566
+ if (!(0, import_node_fs.existsSync)(mp)) die(`motion preset not found: ${catalogEntry.motion}`, 66);
567
+ let raw;
568
+ try {
569
+ raw = JSON.parse((0, import_node_fs.readFileSync)(mp, "utf8"));
570
+ } catch (e) {
571
+ die(`cannot parse motion preset ${catalogEntry.motion}: ${e.message}`, 66);
572
+ }
573
+ const mErrors = validateMotionPreset(raw);
574
+ if (mErrors.length) {
575
+ for (const m of mErrors) process.stderr.write(`deck-build: ERROR motion ${m}
576
+ `);
577
+ die(`${mErrors.length} motion preset error(s) \u2014 nothing written`, 1);
578
+ }
579
+ motionPreset = raw;
580
+ }
581
+ let finalHtml = html;
582
+ if (motionPreset) {
583
+ const perSlide = html.split(/(?=<section\b[^>]*\bclass="[^"]*(?<![\w-])slide(?![\w-]))/).filter(Boolean);
584
+ finalHtml = perSlide.map((sec) => {
585
+ const id = sec.match(/data-layout="([a-z0-9-]+)"/i)?.[1];
586
+ return id ? applyMotion(sec, id, motionPreset) : sec;
587
+ }).join("");
588
+ }
589
+ await (0, import_promises.writeFile)(outPath, finalHtml, "utf8");
322
590
  process.stdout.write(JSON.stringify({
323
591
  ok: true,
324
592
  out: outPath,
325
593
  slides: Array.isArray(spec?.slides) ? spec.slides.length : 0,
326
594
  warnings,
327
- next: `html2pptx ${outPath} out.pptx${style ? ` --style ${style}` : " --style <skin>"}`
595
+ next: `html2pptx ${outPath} out.pptx${styleId ? ` --style ${styleId}` : " --style <skin>"}`
328
596
  }, null, 1) + "\n");
329
597
  }
330
598
  main().catch((e) => die(e.message, 1));
@@ -13795,9 +13795,9 @@ var require_load = __commonJS({
13795
13795
  var require_lib3 = __commonJS({
13796
13796
  "node_modules/jszip/lib/index.js"(exports2, module2) {
13797
13797
  "use strict";
13798
- function JSZip4() {
13799
- if (!(this instanceof JSZip4)) {
13800
- return new JSZip4();
13798
+ function JSZip5() {
13799
+ if (!(this instanceof JSZip5)) {
13800
+ return new JSZip5();
13801
13801
  }
13802
13802
  if (arguments.length) {
13803
13803
  throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");
@@ -13806,7 +13806,7 @@ var require_lib3 = __commonJS({
13806
13806
  this.comment = null;
13807
13807
  this.root = "";
13808
13808
  this.clone = function() {
13809
- var newObj = new JSZip4();
13809
+ var newObj = new JSZip5();
13810
13810
  for (var i in this) {
13811
13811
  if (typeof this[i] !== "function") {
13812
13812
  newObj[i] = this[i];
@@ -13815,16 +13815,16 @@ var require_lib3 = __commonJS({
13815
13815
  return newObj;
13816
13816
  };
13817
13817
  }
13818
- JSZip4.prototype = require_object();
13819
- JSZip4.prototype.loadAsync = require_load();
13820
- JSZip4.support = require_support();
13821
- JSZip4.defaults = require_defaults();
13822
- JSZip4.version = "3.10.1";
13823
- JSZip4.loadAsync = function(content, options) {
13824
- return new JSZip4().loadAsync(content, options);
13818
+ JSZip5.prototype = require_object();
13819
+ JSZip5.prototype.loadAsync = require_load();
13820
+ JSZip5.support = require_support();
13821
+ JSZip5.defaults = require_defaults();
13822
+ JSZip5.version = "3.10.1";
13823
+ JSZip5.loadAsync = function(content, options) {
13824
+ return new JSZip5().loadAsync(content, options);
13825
13825
  };
13826
- JSZip4.external = require_external();
13827
- module2.exports = JSZip4;
13826
+ JSZip5.external = require_external();
13827
+ module2.exports = JSZip5;
13828
13828
  }
13829
13829
  });
13830
13830
 
@@ -16738,7 +16738,7 @@ var require_browser_buffer_encode = __commonJS({
16738
16738
  var require_zip_stream = __commonJS({
16739
16739
  "node_modules/exceljs/lib/utils/zip-stream.js"(exports2, module2) {
16740
16740
  var events = require("events");
16741
- var JSZip4 = require_lib3();
16741
+ var JSZip5 = require_lib3();
16742
16742
  var StreamBuf = require_stream_buf();
16743
16743
  var { stringToBuffer } = require_browser_buffer_encode();
16744
16744
  var ZipWriter = class extends events.EventEmitter {
@@ -16751,7 +16751,7 @@ var require_zip_stream = __commonJS({
16751
16751
  },
16752
16752
  options
16753
16753
  );
16754
- this.zip = new JSZip4();
16754
+ this.zip = new JSZip5();
16755
16755
  this.stream = new StreamBuf();
16756
16756
  }
16757
16757
  append(data, options) {
@@ -28431,7 +28431,7 @@ var require_theme1 = __commonJS({
28431
28431
  var require_xlsx = __commonJS({
28432
28432
  "node_modules/exceljs/lib/xlsx/xlsx.js"(exports2, module2) {
28433
28433
  var fs = require("fs");
28434
- var JSZip4 = require_lib3();
28434
+ var JSZip5 = require_lib3();
28435
28435
  var { PassThrough } = require_readable2();
28436
28436
  var ZipStream = require_zip_stream();
28437
28437
  var StreamBuf = require_stream_buf();
@@ -28670,7 +28670,7 @@ var require_xlsx = __commonJS({
28670
28670
  tables: {},
28671
28671
  vmlDrawings: {}
28672
28672
  };
28673
- const zip = await JSZip4.loadAsync(buffer);
28673
+ const zip = await JSZip5.loadAsync(buffer);
28674
28674
  for (const entry of Object.values(zip.files)) {
28675
28675
  if (!entry.dir) {
28676
28676
  let entryName = entry.name;
@@ -72933,11 +72933,11 @@ var require_excel = __commonJS({
72933
72933
  var require_pptxgen_cjs = __commonJS({
72934
72934
  "node_modules/pptxgenjs/dist/pptxgen.cjs.js"(exports2, module2) {
72935
72935
  "use strict";
72936
- var JSZip4 = require_lib3();
72936
+ var JSZip5 = require_lib3();
72937
72937
  function _interopDefaultLegacy(e) {
72938
72938
  return e && typeof e === "object" && "default" in e ? e : { "default": e };
72939
72939
  }
72940
- var JSZip__default = /* @__PURE__ */ _interopDefaultLegacy(JSZip4);
72940
+ var JSZip__default = /* @__PURE__ */ _interopDefaultLegacy(JSZip5);
72941
72941
  var __assign2 = function() {
72942
72942
  __assign2 = Object.assign || function __assign3(t) {
72943
72943
  for (var s, i = 1, n = arguments.length; i < n; i++) {
@@ -154406,7 +154406,7 @@ function contrastHex(hex) {
154406
154406
  }
154407
154407
 
154408
154408
  // packages/core/dist/document/html-pptx.js
154409
- var import_jszip3 = __toESM(require_lib3(), 1);
154409
+ var import_jszip4 = __toESM(require_lib3(), 1);
154410
154410
 
154411
154411
  // packages/core/dist/document/pptx-anim.js
154412
154412
  var import_jszip2 = __toESM(require_lib3(), 1);
@@ -154447,11 +154447,15 @@ function buildSlideTiming(steps, spidOf) {
154447
154447
  return "";
154448
154448
  let id = 100;
154449
154449
  const next = () => id++;
154450
+ const beatOpened = /* @__PURE__ */ new Set();
154450
154451
  const stepPars = resolved.map(({ s, spid }, i) => {
154451
154452
  const { id: pid, sub } = presetOf(s.effect);
154452
154453
  const dur = Math.max(1, Math.round(s.durMs ?? 500));
154453
- const delay = Math.max(0, Math.round(s.delayMs ?? (i === 0 ? 0 : 200)));
154454
- const node = i === 0 ? "clickEffect" : s.start === "with" ? "withEffect" : "afterEffect";
154454
+ const ridesAlong = s.group !== void 0 && beatOpened.has(s.group);
154455
+ if (s.group !== void 0)
154456
+ beatOpened.add(s.group);
154457
+ const delay = ridesAlong ? 0 : Math.max(0, Math.round(s.delayMs ?? (i === 0 ? 0 : 200)));
154458
+ const node = ridesAlong ? "withEffect" : i === 0 ? "clickEffect" : s.start === "with" ? "withEffect" : "afterEffect";
154455
154459
  const effectCtnId = next();
154456
154460
  const beh = behaviorsOf(s.effect, next, spid, dur);
154457
154461
  return `<p:par><p:cTn id="${effectCtnId}" presetID="${pid}" presetClass="entr" presetSubtype="${sub}" fill="hold" grpId="0" nodeType="${node}"><p:stCondLst><p:cond delay="${delay}"/></p:stCondLst><p:childTnLst>${beh}</p:childTnLst></p:cTn></p:par>`;
@@ -154485,6 +154489,84 @@ async function injectAnimations(buf, perSlide) {
154485
154489
  return await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
154486
154490
  }
154487
154491
 
154492
+ // packages/core/dist/document/pptx-transition.js
154493
+ var import_jszip3 = __toESM(require_lib3(), 1);
154494
+ var MC_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006";
154495
+ var P14_NS = "http://schemas.microsoft.com/office/powerpoint/2010/main";
154496
+ var P159_NS = "http://schemas.microsoft.com/office/powerpoint/2015/09/main";
154497
+ var STANDARD = {
154498
+ cut: { tag: "cut", dirs: null },
154499
+ fade: { tag: "fade", dirs: null },
154500
+ dissolve: { tag: "dissolve", dirs: null },
154501
+ wedge: { tag: "wedge", dirs: null },
154502
+ wipe: { tag: "wipe", dirs: ["l", "r", "u", "d"], defaultDir: "l" },
154503
+ push: { tag: "push", dirs: ["l", "r", "u", "d"], defaultDir: "l" },
154504
+ cover: { tag: "cover", dirs: ["l", "r", "u", "d"], defaultDir: "l" },
154505
+ zoom: { tag: "zoom", dirs: ["in", "out"], defaultDir: "in" },
154506
+ split: { tag: "split", dirs: ["in", "out"], dirAttr: "dir", defaultDir: "in" }
154507
+ };
154508
+ var MORPH = "morph";
154509
+ var TRANSITION_EFFECTS = [...Object.keys(STANDARD), MORPH];
154510
+ function speedOf(durMs) {
154511
+ if (durMs === void 0)
154512
+ return "med";
154513
+ if (durMs >= 1e3)
154514
+ return "slow";
154515
+ if (durMs >= 500)
154516
+ return "med";
154517
+ return "fast";
154518
+ }
154519
+ function effectElement(effect, dir) {
154520
+ const def = STANDARD[effect];
154521
+ if (!def)
154522
+ return "<p:fade/>";
154523
+ if (!def.dirs)
154524
+ return `<p:${def.tag}/>`;
154525
+ const chosen = dir && def.dirs.includes(dir) ? dir : def.defaultDir;
154526
+ return `<p:${def.tag} ${def.dirAttr ?? "dir"}="${chosen}"/>`;
154527
+ }
154528
+ function buildTransition(spec) {
154529
+ const effect = (spec.effect || "").trim();
154530
+ if (!effect || effect === "none")
154531
+ return "";
154532
+ const spd = speedOf(spec.durMs);
154533
+ const dur = spec.durMs !== void 0 ? Math.max(1, Math.round(spec.durMs)) : void 0;
154534
+ const isMorph = effect === MORPH;
154535
+ const plain = `<p:transition spd="${spd}">${effectElement(isMorph ? "fade" : effect, spec.dir)}</p:transition>`;
154536
+ if (!isMorph && dur === void 0)
154537
+ return plain;
154538
+ const choiceNs = isMorph ? ` xmlns:p14="${P14_NS}" xmlns:p159="${P159_NS}" Requires="p159"` : ` xmlns:p14="${P14_NS}" Requires="p14"`;
154539
+ const inner = isMorph ? `<p159:morph option="byObject"/>` : effectElement(effect, spec.dir);
154540
+ const durAttr = dur !== void 0 ? ` p14:dur="${dur}"` : "";
154541
+ return `<mc:AlternateContent xmlns:mc="${MC_NS}"><mc:Choice${choiceNs}><p:transition spd="${spd}"${durAttr}>${inner}</p:transition></mc:Choice><mc:Fallback>${plain}</mc:Fallback></mc:AlternateContent>`;
154542
+ }
154543
+ async function injectTransitions(buf, perSlide) {
154544
+ if (!perSlide.some((t) => t && t.effect && t.effect !== "none"))
154545
+ return buf;
154546
+ const zip = await import_jszip3.default.loadAsync(buf);
154547
+ const slidePaths = Object.keys(zip.files).filter((p) => /^ppt\/slides\/slide\d+\.xml$/.test(p)).sort((a, b) => parseInt(a.match(/(\d+)/)[1], 10) - parseInt(b.match(/(\d+)/)[1], 10));
154548
+ for (let i = 0; i < slidePaths.length; i++) {
154549
+ const spec = perSlide[i];
154550
+ if (!spec)
154551
+ continue;
154552
+ const xml0 = await zip.file(slidePaths[i]).async("string");
154553
+ if (xml0.includes("<p:transition") || xml0.includes("mc:AlternateContent"))
154554
+ continue;
154555
+ const frag = buildTransition(spec);
154556
+ if (!frag)
154557
+ continue;
154558
+ let xml;
154559
+ if (xml0.includes("</p:clrMapOvr>"))
154560
+ xml = xml0.replace("</p:clrMapOvr>", `</p:clrMapOvr>${frag}`);
154561
+ else if (xml0.includes("</p:cSld>"))
154562
+ xml = xml0.replace("</p:cSld>", `</p:cSld>${frag}`);
154563
+ else
154564
+ continue;
154565
+ zip.file(slidePaths[i], xml);
154566
+ }
154567
+ return await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
154568
+ }
154569
+
154488
154570
  // packages/core/dist/document/html-pptx.js
154489
154571
  var DEFAULT_CHART_RAMP = ["2563EB", "10B981", "F59E0B", "EF4444", "8B5CF6", "06B6D4"];
154490
154572
  var SLIDE_W_IN = 13.333;
@@ -154582,7 +154664,7 @@ function gradFillXml(g) {
154582
154664
  return `<a:gradFill rotWithShape="1"><a:gsLst>${gs}</a:gsLst><a:lin ang="${Math.round(deg * 6e4)}" scaled="1"/></a:gradFill>`;
154583
154665
  }
154584
154666
  async function injectGradients(buf, grads) {
154585
- const zip = await import_jszip3.default.loadAsync(buf);
154667
+ const zip = await import_jszip4.default.loadAsync(buf);
154586
154668
  for (const path of Object.keys(zip.files).filter((p) => /^ppt\/slides\/slide\d+\.xml$/.test(p))) {
154587
154669
  let xml = await zip.file(path).async("string");
154588
154670
  let changed = false;
@@ -154650,6 +154732,7 @@ async function convertLayoutToPptx(snapshot) {
154650
154732
  pptx.layout = "TALOS_HTML_WIDE";
154651
154733
  const gradients = [];
154652
154734
  const perSlideAnims = [];
154735
+ const perSlideTransitions = [];
154653
154736
  for (const [slideNo, slideSpec] of snapshot.slides.entries()) {
154654
154737
  const slide = pptx.addSlide();
154655
154738
  const bg = cssColorToHex(slideSpec.background);
@@ -154857,10 +154940,12 @@ async function convertLayoutToPptx(snapshot) {
154857
154940
  if (slideSpec.speakerNotes)
154858
154941
  slide.addNotes(String(slideSpec.speakerNotes));
154859
154942
  perSlideAnims.push(slideAnims);
154943
+ perSlideTransitions.push(slideSpec.transition);
154860
154944
  }
154861
154945
  let buf = await pptx.write("nodebuffer");
154862
154946
  if (gradients.length)
154863
154947
  buf = await injectGradients(buf, gradients);
154948
+ buf = await injectTransitions(buf, perSlideTransitions);
154864
154949
  buf = await injectAnimations(buf, perSlideAnims);
154865
154950
  return { bytes: await finalizePptx(new Uint8Array(buf)), warnings };
154866
154951
  }