@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.
- package/package.json +3 -3
- package/skills/document/SKILL.md +29 -33
- package/skills/document/assets/fonts/Archivo-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/Archivo-SemiBold.woff2 +0 -0
- package/skills/document/assets/fonts/BigShouldersDisplay-Bold.woff2 +0 -0
- package/skills/document/assets/fonts/BodoniModa-SemiBold.woff2 +0 -0
- package/skills/document/assets/fonts/CormorantGaramond-SemiBold.woff2 +0 -0
- package/skills/document/assets/fonts/Fraunces-SemiBold.woff2 +0 -0
- package/skills/document/assets/fonts/GochiHand-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/IBMPlexSans-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/IBMPlexSans-SemiBold.woff2 +0 -0
- package/skills/document/assets/fonts/Inter-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/Jost-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/Jost-SemiBold.woff2 +0 -0
- package/skills/document/assets/fonts/Karla-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/Lora-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/Manrope-Bold.woff2 +0 -0
- package/skills/document/assets/fonts/Manrope-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/Marcellus-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/PublicSans-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/Sora-Regular.woff2 +0 -0
- package/skills/document/assets/fonts/Sora-SemiBold.woff2 +0 -0
- package/skills/document/assets/fonts/fonts.json +218 -0
- package/skills/document/bin/deck-build.cjs +273 -5
- package/skills/document/bin/doc-gen.cjs +108 -23
- package/skills/document/bin/html2pptx.cjs +280 -49
- package/skills/document/catalog.json +25 -0
- package/skills/document/deck-design.md +191 -0
- package/skills/document/layouts/README.md +32 -0
- package/skills/document/layouts/banner-columns.tpl +9 -9
- package/skills/document/layouts/bento.tpl +3 -3
- package/skills/document/layouts/big-stat.tpl +3 -3
- package/skills/document/layouts/blocks-2x2.tpl +12 -12
- package/skills/document/layouts/brand-values.tpl +5 -5
- package/skills/document/layouts/cards-3.tpl +3 -3
- package/skills/document/layouts/cards-grid.tpl +3 -3
- package/skills/document/layouts/chart-full.tpl +3 -3
- package/skills/document/layouts/chart-kpi.tpl +3 -3
- package/skills/document/layouts/color-palette.tpl +5 -5
- package/skills/document/layouts/comparison.tpl +3 -3
- package/skills/document/layouts/concept-hub.tpl +3 -3
- package/skills/document/layouts/cover-centered.tpl +1 -1
- package/skills/document/layouts/cover-image.tpl +1 -1
- package/skills/document/layouts/cover-minimal.tpl +3 -3
- package/skills/document/layouts/cover-statement.tpl +3 -3
- package/skills/document/layouts/cover.tpl +1 -1
- package/skills/document/layouts/data-table.tpl +3 -3
- package/skills/document/layouts/dos-donts.tpl +14 -14
- package/skills/document/layouts/editorial-panel.tpl +11 -11
- package/skills/document/layouts/ending-contact.tpl +1 -1
- package/skills/document/layouts/ending.tpl +1 -1
- package/skills/document/layouts/funnel.tpl +3 -3
- package/skills/document/layouts/gantt.tpl +3 -3
- package/skills/document/layouts/hero.tpl +3 -3
- package/skills/document/layouts/icon-row.tpl +3 -3
- package/skills/document/layouts/image-full.tpl +5 -5
- package/skills/document/layouts/image-grid.tpl +3 -3
- package/skills/document/layouts/image-left.tpl +3 -3
- package/skills/document/layouts/list.tpl +3 -3
- package/skills/document/layouts/logo-guidelines.tpl +8 -8
- package/skills/document/layouts/map-distribution.tpl +3 -3
- package/skills/document/layouts/map-quad.tpl +6 -6
- package/skills/document/layouts/matrix-2x2.tpl +3 -3
- package/skills/document/layouts/numbered-brief.tpl +12 -12
- package/skills/document/layouts/org-tree.tpl +3 -3
- package/skills/document/layouts/problem-solution-banner.tpl +7 -7
- package/skills/document/layouts/problem-solution.tpl +3 -3
- package/skills/document/layouts/pyramid.tpl +3 -3
- package/skills/document/layouts/quote.tpl +1 -1
- package/skills/document/layouts/radar.tpl +3 -3
- package/skills/document/layouts/ring-progress.tpl +3 -3
- package/skills/document/layouts/section-fullbleed.tpl +3 -3
- package/skills/document/layouts/section-image.tpl +1 -1
- package/skills/document/layouts/section-stat.tpl +1 -1
- package/skills/document/layouts/section.tpl +1 -1
- package/skills/document/layouts/slots.json +1 -1
- package/skills/document/layouts/split-two-col.tpl +3 -3
- package/skills/document/layouts/stats-chart.tpl +3 -3
- package/skills/document/layouts/steps-serpentine.tpl +11 -11
- package/skills/document/layouts/steps-vertical.tpl +3 -3
- package/skills/document/layouts/steps.tpl +3 -3
- package/skills/document/layouts/team-row.tpl +4 -4
- package/skills/document/layouts/three-kpi.tpl +3 -3
- package/skills/document/layouts/timeline.tpl +3 -3
- package/skills/document/layouts/title-meta.tpl +5 -5
- package/skills/document/layouts/title.tpl +2 -2
- package/skills/document/layouts/toc-agenda.tpl +3 -3
- package/skills/document/layouts/toc-editorial.tpl +15 -0
- package/skills/document/layouts/toc-panel.tpl +4 -4
- package/skills/document/layouts/toc.tpl +3 -3
- package/skills/document/layouts/transition.tpl +1 -1
- package/skills/document/layouts/two-kpi.tpl +3 -3
- package/skills/document/layouts/type-specimen.tpl +10 -10
- package/skills/document/layouts/versus.tpl +3 -3
- package/skills/document/motion/README.md +11 -0
- package/skills/document/packs/README.md +9 -0
- package/skills/document/styles/README.md +36 -15
- package/skills/document/styles/_contract-defaults.css +55 -0
- package/skills/document/styles/_samples/_groups/biz-premium.webp +0 -0
- package/skills/document/styles/_samples/_groups/creative.webp +0 -0
- package/skills/document/styles/_samples/_groups/editorial.webp +0 -0
- package/skills/document/styles/_samples/_groups/minimal.webp +0 -0
- package/skills/document/styles/_samples/_groups/natural.webp +0 -0
- package/skills/document/styles/_samples/_groups/tech-future.webp +0 -0
- package/skills/document/styles/_samples/anthropic.webp +0 -0
- package/skills/document/styles/_samples/apple.webp +0 -0
- package/skills/document/styles/_samples/black-gold.webp +0 -0
- package/skills/document/styles/_samples/branding.webp +0 -0
- package/skills/document/styles/_samples/cinereel.webp +0 -0
- package/skills/document/styles/_samples/cool.webp +0 -0
- package/skills/document/styles/_samples/hand-drawn.webp +0 -0
- package/skills/document/styles/_samples/ivory-gold.webp +0 -0
- package/skills/document/styles/_samples/magazine-ink.webp +0 -0
- package/skills/document/styles/_samples/mckinsey.webp +0 -0
- package/skills/document/styles/_samples/mono.webp +0 -0
- package/skills/document/styles/_samples/olive-gold.webp +0 -0
- package/skills/document/styles/_samples/swiss-grid.webp +0 -0
- package/skills/document/styles/anthropic/backdrop.html +4 -0
- package/skills/document/styles/anthropic/skin.css +15 -8
- package/skills/document/styles/apple/backdrop.html +4 -1
- package/skills/document/styles/apple/skin.css +5 -2
- package/skills/document/styles/black-gold/backdrop.html +3 -0
- package/skills/document/styles/black-gold/skin.css +15 -8
- package/skills/document/styles/branding/backdrop.html +4 -0
- package/skills/document/styles/branding/skin.css +14 -7
- package/skills/document/styles/cinereel/skin.css +28 -10
- package/skills/document/styles/cool/backdrop.html +3 -0
- package/skills/document/styles/cool/skin.css +5 -2
- package/skills/document/styles/hand-drawn/skin.css +14 -6
- package/skills/document/styles/ivory-gold/skin.css +19 -6
- package/skills/document/styles/magazine-ink/skin.css +6 -1
- package/skills/document/styles/mckinsey/backdrop.html +5 -0
- package/skills/document/styles/mckinsey/skin.css +5 -2
- package/skills/document/styles/mono/backdrop.html +6 -0
- package/skills/document/styles/mono/skin.css +5 -2
- package/skills/document/styles/olive-gold/backdrop.html +5 -0
- package/skills/document/styles/olive-gold/skin.css +15 -8
- package/skills/document/styles/swiss-grid/skin.css +6 -1
|
@@ -9790,9 +9790,9 @@ var require_load = __commonJS({
|
|
|
9790
9790
|
var require_lib3 = __commonJS({
|
|
9791
9791
|
"node_modules/jszip/lib/index.js"(exports2, module2) {
|
|
9792
9792
|
"use strict";
|
|
9793
|
-
function
|
|
9794
|
-
if (!(this instanceof
|
|
9795
|
-
return new
|
|
9793
|
+
function JSZip5() {
|
|
9794
|
+
if (!(this instanceof JSZip5)) {
|
|
9795
|
+
return new JSZip5();
|
|
9796
9796
|
}
|
|
9797
9797
|
if (arguments.length) {
|
|
9798
9798
|
throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");
|
|
@@ -9801,7 +9801,7 @@ var require_lib3 = __commonJS({
|
|
|
9801
9801
|
this.comment = null;
|
|
9802
9802
|
this.root = "";
|
|
9803
9803
|
this.clone = function() {
|
|
9804
|
-
var newObj = new
|
|
9804
|
+
var newObj = new JSZip5();
|
|
9805
9805
|
for (var i in this) {
|
|
9806
9806
|
if (typeof this[i] !== "function") {
|
|
9807
9807
|
newObj[i] = this[i];
|
|
@@ -9810,16 +9810,16 @@ var require_lib3 = __commonJS({
|
|
|
9810
9810
|
return newObj;
|
|
9811
9811
|
};
|
|
9812
9812
|
}
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
return new
|
|
9813
|
+
JSZip5.prototype = require_object();
|
|
9814
|
+
JSZip5.prototype.loadAsync = require_load();
|
|
9815
|
+
JSZip5.support = require_support();
|
|
9816
|
+
JSZip5.defaults = require_defaults();
|
|
9817
|
+
JSZip5.version = "3.10.1";
|
|
9818
|
+
JSZip5.loadAsync = function(content, options) {
|
|
9819
|
+
return new JSZip5().loadAsync(content, options);
|
|
9820
9820
|
};
|
|
9821
|
-
|
|
9822
|
-
module2.exports =
|
|
9821
|
+
JSZip5.external = require_external();
|
|
9822
|
+
module2.exports = JSZip5;
|
|
9823
9823
|
}
|
|
9824
9824
|
});
|
|
9825
9825
|
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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++) {
|
|
@@ -132887,7 +132887,7 @@ var import_node_fs = require("node:fs");
|
|
|
132887
132887
|
var import_node_path = require("node:path");
|
|
132888
132888
|
|
|
132889
132889
|
// packages/core/dist/document/html-pptx.js
|
|
132890
|
-
var
|
|
132890
|
+
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
132891
132891
|
|
|
132892
132892
|
// packages/core/dist/document/pptx-anim.js
|
|
132893
132893
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
@@ -132928,11 +132928,15 @@ function buildSlideTiming(steps, spidOf) {
|
|
|
132928
132928
|
return "";
|
|
132929
132929
|
let id = 100;
|
|
132930
132930
|
const next = () => id++;
|
|
132931
|
+
const beatOpened = /* @__PURE__ */ new Set();
|
|
132931
132932
|
const stepPars = resolved.map(({ s, spid }, i) => {
|
|
132932
132933
|
const { id: pid, sub } = presetOf(s.effect);
|
|
132933
132934
|
const dur = Math.max(1, Math.round(s.durMs ?? 500));
|
|
132934
|
-
const
|
|
132935
|
-
|
|
132935
|
+
const ridesAlong = s.group !== void 0 && beatOpened.has(s.group);
|
|
132936
|
+
if (s.group !== void 0)
|
|
132937
|
+
beatOpened.add(s.group);
|
|
132938
|
+
const delay = ridesAlong ? 0 : Math.max(0, Math.round(s.delayMs ?? (i === 0 ? 0 : 200)));
|
|
132939
|
+
const node = ridesAlong ? "withEffect" : i === 0 ? "clickEffect" : s.start === "with" ? "withEffect" : "afterEffect";
|
|
132936
132940
|
const effectCtnId = next();
|
|
132937
132941
|
const beh = behaviorsOf(s.effect, next, spid, dur);
|
|
132938
132942
|
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>`;
|
|
@@ -132966,6 +132970,84 @@ async function injectAnimations(buf, perSlide) {
|
|
|
132966
132970
|
return await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
|
|
132967
132971
|
}
|
|
132968
132972
|
|
|
132973
|
+
// packages/core/dist/document/pptx-transition.js
|
|
132974
|
+
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
132975
|
+
var MC_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006";
|
|
132976
|
+
var P14_NS = "http://schemas.microsoft.com/office/powerpoint/2010/main";
|
|
132977
|
+
var P159_NS = "http://schemas.microsoft.com/office/powerpoint/2015/09/main";
|
|
132978
|
+
var STANDARD = {
|
|
132979
|
+
cut: { tag: "cut", dirs: null },
|
|
132980
|
+
fade: { tag: "fade", dirs: null },
|
|
132981
|
+
dissolve: { tag: "dissolve", dirs: null },
|
|
132982
|
+
wedge: { tag: "wedge", dirs: null },
|
|
132983
|
+
wipe: { tag: "wipe", dirs: ["l", "r", "u", "d"], defaultDir: "l" },
|
|
132984
|
+
push: { tag: "push", dirs: ["l", "r", "u", "d"], defaultDir: "l" },
|
|
132985
|
+
cover: { tag: "cover", dirs: ["l", "r", "u", "d"], defaultDir: "l" },
|
|
132986
|
+
zoom: { tag: "zoom", dirs: ["in", "out"], defaultDir: "in" },
|
|
132987
|
+
split: { tag: "split", dirs: ["in", "out"], dirAttr: "dir", defaultDir: "in" }
|
|
132988
|
+
};
|
|
132989
|
+
var MORPH = "morph";
|
|
132990
|
+
var TRANSITION_EFFECTS = [...Object.keys(STANDARD), MORPH];
|
|
132991
|
+
function speedOf(durMs) {
|
|
132992
|
+
if (durMs === void 0)
|
|
132993
|
+
return "med";
|
|
132994
|
+
if (durMs >= 1e3)
|
|
132995
|
+
return "slow";
|
|
132996
|
+
if (durMs >= 500)
|
|
132997
|
+
return "med";
|
|
132998
|
+
return "fast";
|
|
132999
|
+
}
|
|
133000
|
+
function effectElement(effect, dir) {
|
|
133001
|
+
const def = STANDARD[effect];
|
|
133002
|
+
if (!def)
|
|
133003
|
+
return "<p:fade/>";
|
|
133004
|
+
if (!def.dirs)
|
|
133005
|
+
return `<p:${def.tag}/>`;
|
|
133006
|
+
const chosen = dir && def.dirs.includes(dir) ? dir : def.defaultDir;
|
|
133007
|
+
return `<p:${def.tag} ${def.dirAttr ?? "dir"}="${chosen}"/>`;
|
|
133008
|
+
}
|
|
133009
|
+
function buildTransition(spec) {
|
|
133010
|
+
const effect = (spec.effect || "").trim();
|
|
133011
|
+
if (!effect || effect === "none")
|
|
133012
|
+
return "";
|
|
133013
|
+
const spd = speedOf(spec.durMs);
|
|
133014
|
+
const dur = spec.durMs !== void 0 ? Math.max(1, Math.round(spec.durMs)) : void 0;
|
|
133015
|
+
const isMorph = effect === MORPH;
|
|
133016
|
+
const plain = `<p:transition spd="${spd}">${effectElement(isMorph ? "fade" : effect, spec.dir)}</p:transition>`;
|
|
133017
|
+
if (!isMorph && dur === void 0)
|
|
133018
|
+
return plain;
|
|
133019
|
+
const choiceNs = isMorph ? ` xmlns:p14="${P14_NS}" xmlns:p159="${P159_NS}" Requires="p159"` : ` xmlns:p14="${P14_NS}" Requires="p14"`;
|
|
133020
|
+
const inner = isMorph ? `<p159:morph option="byObject"/>` : effectElement(effect, spec.dir);
|
|
133021
|
+
const durAttr = dur !== void 0 ? ` p14:dur="${dur}"` : "";
|
|
133022
|
+
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>`;
|
|
133023
|
+
}
|
|
133024
|
+
async function injectTransitions(buf, perSlide) {
|
|
133025
|
+
if (!perSlide.some((t) => t && t.effect && t.effect !== "none"))
|
|
133026
|
+
return buf;
|
|
133027
|
+
const zip = await import_jszip2.default.loadAsync(buf);
|
|
133028
|
+
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));
|
|
133029
|
+
for (let i = 0; i < slidePaths.length; i++) {
|
|
133030
|
+
const spec = perSlide[i];
|
|
133031
|
+
if (!spec)
|
|
133032
|
+
continue;
|
|
133033
|
+
const xml0 = await zip.file(slidePaths[i]).async("string");
|
|
133034
|
+
if (xml0.includes("<p:transition") || xml0.includes("mc:AlternateContent"))
|
|
133035
|
+
continue;
|
|
133036
|
+
const frag = buildTransition(spec);
|
|
133037
|
+
if (!frag)
|
|
133038
|
+
continue;
|
|
133039
|
+
let xml;
|
|
133040
|
+
if (xml0.includes("</p:clrMapOvr>"))
|
|
133041
|
+
xml = xml0.replace("</p:clrMapOvr>", `</p:clrMapOvr>${frag}`);
|
|
133042
|
+
else if (xml0.includes("</p:cSld>"))
|
|
133043
|
+
xml = xml0.replace("</p:cSld>", `</p:cSld>${frag}`);
|
|
133044
|
+
else
|
|
133045
|
+
continue;
|
|
133046
|
+
zip.file(slidePaths[i], xml);
|
|
133047
|
+
}
|
|
133048
|
+
return await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
|
|
133049
|
+
}
|
|
133050
|
+
|
|
132969
133051
|
// node_modules/docx/dist/index.mjs
|
|
132970
133052
|
var __create2 = Object.create;
|
|
132971
133053
|
var __defProp2 = Object.defineProperty;
|
|
@@ -146661,7 +146743,7 @@ var findPatchKeys = (text) => {
|
|
|
146661
146743
|
|
|
146662
146744
|
// packages/core/dist/document/doc-gen.js
|
|
146663
146745
|
var import_exceljs = __toESM(require_excel(), 1);
|
|
146664
|
-
var
|
|
146746
|
+
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
146665
146747
|
var import_pptxgenjs = __toESM(require_pptxgen_cjs(), 1);
|
|
146666
146748
|
var import_pdf_lib = __toESM(require_cjs(), 1);
|
|
146667
146749
|
var import_fontkit = __toESM(require_fontkit_umd(), 1);
|
|
@@ -147060,7 +147142,7 @@ async function finalizePptx(bytes) {
|
|
|
147060
147142
|
return stripDanglingOverrides(await normalizeChartParts(bytes));
|
|
147061
147143
|
}
|
|
147062
147144
|
async function normalizeChartParts(bytes) {
|
|
147063
|
-
const zip = await
|
|
147145
|
+
const zip = await import_jszip3.default.loadAsync(Buffer.from(bytes));
|
|
147064
147146
|
const pres = zip.file("ppt/presentation.xml");
|
|
147065
147147
|
if (pres) {
|
|
147066
147148
|
let xml = await pres.async("string");
|
|
@@ -147113,7 +147195,7 @@ async function normalizeChartParts(bytes) {
|
|
|
147113
147195
|
return new Uint8Array(out);
|
|
147114
147196
|
}
|
|
147115
147197
|
async function stripDanglingOverrides(bytes) {
|
|
147116
|
-
const zip = await
|
|
147198
|
+
const zip = await import_jszip3.default.loadAsync(Buffer.from(bytes));
|
|
147117
147199
|
const ctFile = zip.file("[Content_Types].xml");
|
|
147118
147200
|
if (!ctFile)
|
|
147119
147201
|
return bytes;
|
|
@@ -147274,7 +147356,7 @@ function gradFillXml(g) {
|
|
|
147274
147356
|
return `<a:gradFill rotWithShape="1"><a:gsLst>${gs}</a:gsLst><a:lin ang="${Math.round(deg * 6e4)}" scaled="1"/></a:gradFill>`;
|
|
147275
147357
|
}
|
|
147276
147358
|
async function injectGradients(buf, grads) {
|
|
147277
|
-
const zip = await
|
|
147359
|
+
const zip = await import_jszip4.default.loadAsync(buf);
|
|
147278
147360
|
for (const path of Object.keys(zip.files).filter((p) => /^ppt\/slides\/slide\d+\.xml$/.test(p))) {
|
|
147279
147361
|
let xml = await zip.file(path).async("string");
|
|
147280
147362
|
let changed = false;
|
|
@@ -147342,6 +147424,7 @@ async function convertLayoutToPptx(snapshot) {
|
|
|
147342
147424
|
pptx.layout = "TALOS_HTML_WIDE";
|
|
147343
147425
|
const gradients = [];
|
|
147344
147426
|
const perSlideAnims = [];
|
|
147427
|
+
const perSlideTransitions = [];
|
|
147345
147428
|
for (const [slideNo, slideSpec] of snapshot.slides.entries()) {
|
|
147346
147429
|
const slide = pptx.addSlide();
|
|
147347
147430
|
const bg = cssColorToHex(slideSpec.background);
|
|
@@ -147549,10 +147632,12 @@ async function convertLayoutToPptx(snapshot) {
|
|
|
147549
147632
|
if (slideSpec.speakerNotes)
|
|
147550
147633
|
slide.addNotes(String(slideSpec.speakerNotes));
|
|
147551
147634
|
perSlideAnims.push(slideAnims);
|
|
147635
|
+
perSlideTransitions.push(slideSpec.transition);
|
|
147552
147636
|
}
|
|
147553
147637
|
let buf = await pptx.write("nodebuffer");
|
|
147554
147638
|
if (gradients.length)
|
|
147555
147639
|
buf = await injectGradients(buf, gradients);
|
|
147640
|
+
buf = await injectTransitions(buf, perSlideTransitions);
|
|
147556
147641
|
buf = await injectAnimations(buf, perSlideAnims);
|
|
147557
147642
|
return { bytes: await finalizePptx(new Uint8Array(buf)), warnings };
|
|
147558
147643
|
}
|
|
@@ -147585,15 +147670,20 @@ var LAYOUT_WALKER_JS = `
|
|
|
147585
147670
|
// Entrance-animation intent: an element (or, for text, its nearest ancestor)
|
|
147586
147671
|
// carrying data-anim="<effect>" [+ -seq/-start/-delay/-dur]. Emitted as {anim}
|
|
147587
147672
|
// on the element snapshot; turned into a native <p:timing> step post-write.
|
|
147673
|
+
// Every element resolving to the same host gets that host's group id, so the
|
|
147674
|
+
// builder can collapse them into one beat instead of one step per text run.
|
|
147675
|
+
const animHosts = [];
|
|
147588
147676
|
const animOf = (elm) => {
|
|
147589
147677
|
if (!elm || !elm.getAttribute) return undefined;
|
|
147590
147678
|
const host = elm.getAttribute("data-anim") ? elm : (elm.closest ? elm.closest("[data-anim]") : null);
|
|
147591
147679
|
if (!host) return undefined;
|
|
147592
147680
|
const effect = (host.getAttribute("data-anim") || "").trim();
|
|
147593
147681
|
if (!effect) return undefined;
|
|
147682
|
+
let group = animHosts.indexOf(host);
|
|
147683
|
+
if (group < 0) { group = animHosts.length; animHosts.push(host); }
|
|
147594
147684
|
const num = (a) => { const v = parseFloat(host.getAttribute(a)); return Number.isFinite(v) ? v : undefined; };
|
|
147595
147685
|
const start = host.getAttribute("data-anim-start");
|
|
147596
|
-
const o = { effect: effect };
|
|
147686
|
+
const o = { effect: effect, group: group };
|
|
147597
147687
|
const seq = num("data-anim-seq"); if (seq !== undefined) o.seq = seq;
|
|
147598
147688
|
if (start === "with" || start === "onclick" || start === "after") o.start = start;
|
|
147599
147689
|
const d = num("data-anim-delay"); if (d !== undefined) o.delayMs = d;
|
|
@@ -147716,7 +147806,17 @@ var LAYOUT_WALKER_JS = `
|
|
|
147716
147806
|
// data-notes attribute \u2192 pptx notesSlide (Stage B addNotes).
|
|
147717
147807
|
const notesEl = sec.querySelector(".talos-notes");
|
|
147718
147808
|
const speakerNotes = (((notesEl && notesEl.textContent) || sec.getAttribute("data-notes") || "").trim()) || undefined;
|
|
147719
|
-
|
|
147809
|
+
// Slide transition: how the deck moves INTO this slide \u2192 native <p:transition>.
|
|
147810
|
+
const trEffect = (sec.getAttribute("data-transition") || "").trim();
|
|
147811
|
+
let transition;
|
|
147812
|
+
if (trEffect) {
|
|
147813
|
+
transition = { effect: trEffect };
|
|
147814
|
+
const trDur = parseFloat(sec.getAttribute("data-transition-dur"));
|
|
147815
|
+
if (Number.isFinite(trDur)) transition.durMs = trDur;
|
|
147816
|
+
const trDir = (sec.getAttribute("data-transition-dir") || "").trim();
|
|
147817
|
+
if (trDir) transition.dir = trDir;
|
|
147818
|
+
}
|
|
147819
|
+
return { background: color(getComputedStyle(sec).backgroundColor) ?? "#ffffff", elements, ...(speakerNotes ? { speakerNotes } : {}), ...(transition ? { transition } : {}) };
|
|
147720
147820
|
});
|
|
147721
147821
|
return { width: 1280, height: 720, slides, notes };
|
|
147722
147822
|
})()
|
|
@@ -147844,6 +147944,90 @@ async function inlineHtmlImages(html, resolve) {
|
|
|
147844
147944
|
return { html: out, inlined, skipped };
|
|
147845
147945
|
}
|
|
147846
147946
|
|
|
147947
|
+
// packages/core/dist/document/deck-catalog.js
|
|
147948
|
+
var KINDS = ["skin", "pack"];
|
|
147949
|
+
var MODES = ["light", "dark"];
|
|
147950
|
+
var ID_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
147951
|
+
function isStr(v) {
|
|
147952
|
+
return typeof v === "string" && v.length > 0;
|
|
147953
|
+
}
|
|
147954
|
+
function isStrArr(v) {
|
|
147955
|
+
return Array.isArray(v) && v.every((x) => typeof x === "string");
|
|
147956
|
+
}
|
|
147957
|
+
function parseCatalog(raw) {
|
|
147958
|
+
const errors = [];
|
|
147959
|
+
const o = raw;
|
|
147960
|
+
if (!o || typeof o !== "object")
|
|
147961
|
+
return { catalog: null, errors: ["catalog is not an object"] };
|
|
147962
|
+
const groups = [];
|
|
147963
|
+
const rawGroups = Array.isArray(o.groups) ? o.groups : [];
|
|
147964
|
+
if (!Array.isArray(o.groups))
|
|
147965
|
+
errors.push("catalog.groups must be an array");
|
|
147966
|
+
rawGroups.forEach((g, i) => {
|
|
147967
|
+
const at = `group[${i}]`;
|
|
147968
|
+
if (!isStr(g?.id) || !ID_RE.test(g.id))
|
|
147969
|
+
errors.push(`${at}: bad id`);
|
|
147970
|
+
if (!isStr(g?.name_cn))
|
|
147971
|
+
errors.push(`${at}: missing name_cn`);
|
|
147972
|
+
if (!isStr(g?.sample))
|
|
147973
|
+
errors.push(`${at}: missing sample`);
|
|
147974
|
+
if (!isStrArr(g?.scenarios))
|
|
147975
|
+
errors.push(`${at}: scenarios must be a string array`);
|
|
147976
|
+
if (isStr(g?.id) && isStr(g?.name_cn) && isStr(g?.sample) && isStrArr(g?.scenarios)) {
|
|
147977
|
+
groups.push({ id: g.id, name_cn: g.name_cn, sample: g.sample, scenarios: g.scenarios });
|
|
147978
|
+
}
|
|
147979
|
+
});
|
|
147980
|
+
const entries = [];
|
|
147981
|
+
const rawEntries = Array.isArray(o.entries) ? o.entries : [];
|
|
147982
|
+
if (!Array.isArray(o.entries))
|
|
147983
|
+
errors.push("catalog.entries must be an array");
|
|
147984
|
+
rawEntries.forEach((e, i) => {
|
|
147985
|
+
const at = `entry[${i}]${isStr(e?.id) ? ` (${e.id})` : ""}`;
|
|
147986
|
+
const before = errors.length;
|
|
147987
|
+
if (!isStr(e?.id) || !ID_RE.test(e.id))
|
|
147988
|
+
errors.push(`${at}: bad id`);
|
|
147989
|
+
if (!isStr(e?.kind) || !KINDS.includes(e.kind))
|
|
147990
|
+
errors.push(`${at}: kind must be "skin" or "pack"`);
|
|
147991
|
+
if (!isStr(e?.group))
|
|
147992
|
+
errors.push(`${at}: missing group`);
|
|
147993
|
+
if (!isStr(e?.name_cn))
|
|
147994
|
+
errors.push(`${at}: missing name_cn`);
|
|
147995
|
+
if (!isStr(e?.oneliner))
|
|
147996
|
+
errors.push(`${at}: missing oneliner`);
|
|
147997
|
+
if (!isStrArr(e?.scenarios))
|
|
147998
|
+
errors.push(`${at}: scenarios must be a string array`);
|
|
147999
|
+
if (!isStr(e?.mode) || !MODES.includes(e.mode))
|
|
148000
|
+
errors.push(`${at}: mode must be "light" or "dark"`);
|
|
148001
|
+
if (!isStr(e?.sample))
|
|
148002
|
+
errors.push(`${at}: missing sample`);
|
|
148003
|
+
if (e?.motion !== void 0 && !isStr(e.motion))
|
|
148004
|
+
errors.push(`${at}: motion must be a string when present`);
|
|
148005
|
+
if (errors.length === before) {
|
|
148006
|
+
entries.push({
|
|
148007
|
+
id: e.id,
|
|
148008
|
+
kind: e.kind,
|
|
148009
|
+
group: e.group,
|
|
148010
|
+
name_cn: e.name_cn,
|
|
148011
|
+
oneliner: e.oneliner,
|
|
148012
|
+
scenarios: e.scenarios,
|
|
148013
|
+
mode: e.mode,
|
|
148014
|
+
sample: e.sample,
|
|
148015
|
+
...e.motion !== void 0 ? { motion: e.motion } : {}
|
|
148016
|
+
});
|
|
148017
|
+
}
|
|
148018
|
+
});
|
|
148019
|
+
return { catalog: errors.length ? null : { groups, entries }, errors };
|
|
148020
|
+
}
|
|
148021
|
+
function resolveEntry(catalog, id) {
|
|
148022
|
+
return catalog.entries.find((e) => e.id === id) ?? null;
|
|
148023
|
+
}
|
|
148024
|
+
function assetDirOf(entry) {
|
|
148025
|
+
return entry.kind === "skin" ? `styles/${entry.id}` : `packs/${entry.id}`;
|
|
148026
|
+
}
|
|
148027
|
+
function cssFileOf(entry) {
|
|
148028
|
+
return entry.kind === "skin" ? "skin.css" : "pack.css";
|
|
148029
|
+
}
|
|
148030
|
+
|
|
147847
148031
|
// apps/admin/data/skills.lib/document/bin-src/html2pptx.mjs
|
|
147848
148032
|
function imageResolver(baseDir) {
|
|
147849
148033
|
return async (src) => {
|
|
@@ -147869,27 +148053,52 @@ async function tailwindCss() {
|
|
|
147869
148053
|
_tailwindCss = (0, import_node_fs.existsSync)(file) ? await (0, import_promises.readFile)(file, "utf8").catch(() => "") : "";
|
|
147870
148054
|
return _tailwindCss;
|
|
147871
148055
|
}
|
|
147872
|
-
var CJK_RE2 = /[
|
|
147873
|
-
var
|
|
147874
|
-
|
|
147875
|
-
|
|
148056
|
+
var CJK_RE2 = /[\u2E80-\u2FFF\u3000-\u303F\u3040-\u30FF\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF\uFF00-\uFFEF]/;
|
|
148057
|
+
var _fontManifest;
|
|
148058
|
+
async function fontManifest() {
|
|
148059
|
+
if (_fontManifest !== void 0) return _fontManifest;
|
|
148060
|
+
const dir = process.env.TALOS_CJK_FONT_DIR || (0, import_node_path.join)((0, import_node_path.dirname)(process.argv[1]), "..", "assets", "fonts");
|
|
148061
|
+
const file = (0, import_node_path.join)(dir, "fonts.json");
|
|
148062
|
+
try {
|
|
148063
|
+
_fontManifest = { dir, ...JSON.parse(await (0, import_promises.readFile)(file, "utf8")) };
|
|
148064
|
+
} catch {
|
|
148065
|
+
_fontManifest = { dir, cjk: [], latin: [], cjkUnicodeRange: "" };
|
|
148066
|
+
}
|
|
148067
|
+
return _fontManifest;
|
|
148068
|
+
}
|
|
148069
|
+
async function faceCss(entries, range) {
|
|
148070
|
+
const { dir } = await fontManifest();
|
|
148071
|
+
const rules = [];
|
|
148072
|
+
for (const entry of entries ?? []) {
|
|
148073
|
+
const path = (0, import_node_path.join)(dir, entry.file);
|
|
148074
|
+
if (!(0, import_node_fs.existsSync)(path)) continue;
|
|
148075
|
+
const b64 = (await (0, import_promises.readFile)(path).catch(() => null))?.toString("base64");
|
|
148076
|
+
if (!b64) continue;
|
|
148077
|
+
for (const family of entry.families ?? []) {
|
|
148078
|
+
rules.push(
|
|
148079
|
+
`@font-face{font-family:'${family}';src:local('${family}'),url(data:font/woff2;base64,${b64}) format('woff2');${entry.weight ? `font-weight:${entry.weight};` : ""}${range ? `unicode-range:${range};` : ""}font-display:swap}`
|
|
148080
|
+
);
|
|
148081
|
+
}
|
|
148082
|
+
}
|
|
148083
|
+
return rules.join("");
|
|
148084
|
+
}
|
|
147876
148085
|
var _cjkFontCss;
|
|
147877
148086
|
async function cjkFontFaceCss() {
|
|
147878
|
-
if (_cjkFontCss
|
|
147879
|
-
|
|
147880
|
-
|
|
147881
|
-
|
|
147882
|
-
return (0, import_node_fs.existsSync)(p) ? (await (0, import_promises.readFile)(p).catch(() => null))?.toString("base64") : null;
|
|
147883
|
-
};
|
|
147884
|
-
const [sans, serif] = await Promise.all([enc("NotoSansSC.woff2"), enc("NotoSerifSC.woff2")]);
|
|
147885
|
-
const face = (family, b64) => b64 ? `@font-face{font-family:'${family}';src:local('${family}'),url(data:font/woff2;base64,${b64}) format('woff2');unicode-range:${CJK_UNICODE_RANGE};font-display:swap}` : "";
|
|
147886
|
-
const rules = [
|
|
147887
|
-
...CJK_SANS_FAMILIES.map((f) => face(f, sans)),
|
|
147888
|
-
...CJK_SERIF_FAMILIES.map((f) => face(f, serif))
|
|
147889
|
-
].filter(Boolean);
|
|
147890
|
-
_cjkFontCss = rules.join("");
|
|
148087
|
+
if (_cjkFontCss === void 0) {
|
|
148088
|
+
const m = await fontManifest();
|
|
148089
|
+
_cjkFontCss = await faceCss(m.cjk, m.cjkUnicodeRange);
|
|
148090
|
+
}
|
|
147891
148091
|
return _cjkFontCss;
|
|
147892
148092
|
}
|
|
148093
|
+
var _latinFontCss;
|
|
148094
|
+
async function latinFontFaceCss(doc) {
|
|
148095
|
+
if (_latinFontCss === void 0) {
|
|
148096
|
+
const m = await fontManifest();
|
|
148097
|
+
const wanted = (m.latin ?? []).filter((e) => (e.families ?? []).some((f) => doc.includes(f)));
|
|
148098
|
+
_latinFontCss = await faceCss(wanted, void 0);
|
|
148099
|
+
}
|
|
148100
|
+
return _latinFontCss;
|
|
148101
|
+
}
|
|
147893
148102
|
async function withHeadlessPage(html, fn) {
|
|
147894
148103
|
const headless = (process.env.TALOS_HTML2PPTX_HEADLESS ?? "").trim().toLowerCase();
|
|
147895
148104
|
if (headless === "off" || headless === "none" || headless === "0" || headless === "false") return null;
|
|
@@ -148004,7 +148213,7 @@ async function main() {
|
|
|
148004
148213
|
process.stdout.write(JSON.stringify({ ok: true, out, engine: "layout-json", slides: snapshot2.slides?.length ?? 0, ...notesDocPath ? { notesDoc: notesDocPath } : {}, warnings: warnings2 }, null, 1) + "\n");
|
|
148005
148214
|
return;
|
|
148006
148215
|
}
|
|
148007
|
-
if (
|
|
148216
|
+
if (!/<section[^>]*\bclass="[^"]*(?<![\w-])slide(?![\w-])/.test(raw)) {
|
|
148008
148217
|
die('the HTML must contain one <section class="slide"> per slide (1280\xD7720 canvas) \u2014 see deck-design.md', 65);
|
|
148009
148218
|
}
|
|
148010
148219
|
const colorWarnings = [...lintHardcodedColors(raw), ...lintRepeatedLayouts(raw)];
|
|
@@ -148028,13 +148237,33 @@ async function main() {
|
|
|
148028
148237
|
let skinCss = "", backdropHtml = "", skinAccent = "", skinAxis = "", skinChart1 = "";
|
|
148029
148238
|
if (styleArg) {
|
|
148030
148239
|
const skillDir = (0, import_node_path.dirname)((0, import_node_path.dirname)(process.argv[1] || ""));
|
|
148031
|
-
|
|
148032
|
-
|
|
148240
|
+
let styleDir, cssName = "skin.css";
|
|
148241
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(styleArg, "skin.css"))) {
|
|
148242
|
+
styleDir = styleArg;
|
|
148243
|
+
} else if ((0, import_node_fs.existsSync)((0, import_node_path.join)(styleArg, "pack.css"))) {
|
|
148244
|
+
styleDir = styleArg;
|
|
148245
|
+
cssName = "pack.css";
|
|
148246
|
+
} else {
|
|
148247
|
+
let entry = null;
|
|
148248
|
+
const catalogPath = (0, import_node_path.join)(skillDir, "catalog.json");
|
|
148249
|
+
if ((0, import_node_fs.existsSync)(catalogPath)) {
|
|
148250
|
+
try {
|
|
148251
|
+
const { catalog } = parseCatalog(JSON.parse((0, import_node_fs.readFileSync)(catalogPath, "utf8")));
|
|
148252
|
+
if (catalog) entry = resolveEntry(catalog, styleArg);
|
|
148253
|
+
} catch {
|
|
148254
|
+
}
|
|
148255
|
+
}
|
|
148256
|
+
styleDir = entry ? (0, import_node_path.join)(skillDir, assetDirOf(entry)) : (0, import_node_path.join)(skillDir, "styles", styleArg);
|
|
148257
|
+
if (entry) cssName = cssFileOf(entry);
|
|
148258
|
+
}
|
|
148259
|
+
const skinPath = (0, import_node_path.join)(styleDir, cssName);
|
|
148033
148260
|
try {
|
|
148034
148261
|
skinCss = await (0, import_promises.readFile)(skinPath, "utf8");
|
|
148035
148262
|
} catch (e) {
|
|
148036
148263
|
die(`cannot read style ${skinPath}: ${e.message}`, 66);
|
|
148037
148264
|
}
|
|
148265
|
+
const defaultsPath = (0, import_node_path.join)(skillDir, "styles", "_contract-defaults.css");
|
|
148266
|
+
if ((0, import_node_fs.existsSync)(defaultsPath)) skinCss = await (0, import_promises.readFile)(defaultsPath, "utf8") + "\n" + skinCss;
|
|
148038
148267
|
const sharedBackdropsDir = (0, import_node_path.join)(skillDir, "styles", "_backdrops");
|
|
148039
148268
|
const NO_AUTO_BACKDROP_VARIETY = /* @__PURE__ */ new Set(["mckinsey", "mono", "cinereel"]);
|
|
148040
148269
|
let bdPath;
|
|
@@ -148089,7 +148318,9 @@ async function main() {
|
|
|
148089
148318
|
}
|
|
148090
148319
|
const tw = await tailwindCss();
|
|
148091
148320
|
const cjk = !hasService && CJK_RE2.test(rawInlined) ? await cjkFontFaceCss() : "";
|
|
148092
|
-
const
|
|
148321
|
+
const latin = await latinFontFaceCss(rawInlined + skinCss);
|
|
148322
|
+
const fontCss = cjk + latin;
|
|
148323
|
+
const html = injectHead(rawInlined, `${fontCss ? `<style>${fontCss}</style>` : ""}${tw ? `<style>${tw}</style>` : ""}<style>${themeCss}${SKELETON_CSS}${skinCss}</style>`);
|
|
148093
148324
|
if (rasterize) {
|
|
148094
148325
|
let images;
|
|
148095
148326
|
if (hasService) ({ images } = await callService("/shot", html).catch((e) => die(e.message, 1)));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"groups": [
|
|
3
|
+
{ "id": "tech-future", "name_cn": "科技未来", "sample": "styles/_samples/_groups/tech-future.webp", "scenarios": ["科技", "发布会", "产品", "pitch"] },
|
|
4
|
+
{ "id": "biz-premium", "name_cn": "商务高端", "sample": "styles/_samples/_groups/biz-premium.webp", "scenarios": ["金融", "年报", "路演", "招商", "董事会"] },
|
|
5
|
+
{ "id": "minimal", "name_cn": "极简设计", "sample": "styles/_samples/_groups/minimal.webp", "scenarios": ["极简", "设计", "作品集"] },
|
|
6
|
+
{ "id": "editorial", "name_cn": "编辑人文", "sample": "styles/_samples/_groups/editorial.webp", "scenarios": ["人文", "行业观察", "杂志感", "研究分享"] },
|
|
7
|
+
{ "id": "creative", "name_cn": "创意手作", "sample": "styles/_samples/_groups/creative.webp", "scenarios": ["创意", "教学", "工作坊", "头脑风暴"] },
|
|
8
|
+
{ "id": "natural", "name_cn": "自然温和", "sample": "styles/_samples/_groups/natural.webp", "scenarios": ["品牌手册", "可持续", "美妆", "零售"] }
|
|
9
|
+
],
|
|
10
|
+
"entries": [
|
|
11
|
+
{ "id": "cool", "kind": "skin", "group": "tech-future", "name_cn": "酷炫深色", "oneliner": "深蓝辉光 · 科技发布", "scenarios": ["科技", "发布", "pitch", "主题演讲"], "mode": "dark", "sample": "styles/_samples/cool.webp" },
|
|
12
|
+
{ "id": "swiss-grid", "kind": "skin", "group": "tech-future", "name_cn": "瑞士国际", "oneliner": "克莱因蓝白 · 瑞士国际", "scenarios": ["科技产品", "数据汇报", "设计", "年度总结"], "mode": "light", "sample": "styles/_samples/swiss-grid.webp" },
|
|
13
|
+
{ "id": "black-gold", "kind": "skin", "group": "biz-premium", "name_cn": "黑金", "oneliner": "纯黑金辉 · 高端商务", "scenarios": ["金融", "年报", "路演", "奢侈品"], "mode": "dark", "sample": "styles/_samples/black-gold.webp" },
|
|
14
|
+
{ "id": "olive-gold", "kind": "skin", "group": "biz-premium", "name_cn": "橄榄金", "oneliner": "橄榄亮金 · 高端招商", "scenarios": ["高端", "证书", "招商", "品牌"], "mode": "dark", "sample": "styles/_samples/olive-gold.webp" },
|
|
15
|
+
{ "id": "mckinsey", "kind": "skin", "group": "biz-premium", "name_cn": "白底咨询", "oneliner": "白底藏青 · 咨询评审", "scenarios": ["咨询", "战略汇报", "评审", "董事会"], "mode": "light", "sample": "styles/_samples/mckinsey.webp" },
|
|
16
|
+
{ "id": "apple", "kind": "skin", "group": "minimal", "name_cn": "纯黑极简", "oneliner": "纯黑极简 · 产品发布", "scenarios": ["产品发布", "主题演讲", "极简演示"], "mode": "dark", "sample": "styles/_samples/apple.webp" },
|
|
17
|
+
{ "id": "mono", "kind": "skin", "group": "minimal", "name_cn": "纯白黑灰", "oneliner": "纯白黑灰 · 极简设计", "scenarios": ["极简", "高端", "设计", "单色报告"], "mode": "light", "sample": "styles/_samples/mono.webp" },
|
|
18
|
+
{ "id": "ivory-gold", "kind": "skin", "group": "minimal", "name_cn": "奶油青铜", "oneliner": "奶油青铜 · 奢华极简", "scenarios": ["奢华极简", "品牌手册", "路演", "高端零售"], "mode": "light", "sample": "styles/_samples/ivory-gold.webp" },
|
|
19
|
+
{ "id": "magazine-ink", "kind": "skin", "group": "editorial", "name_cn": "杂志墨", "oneliner": "瓷白靛蓝 · 杂志人文", "scenarios": ["人文分享", "行业观察", "商业发布"], "mode": "light", "sample": "styles/_samples/magazine-ink.webp" },
|
|
20
|
+
{ "id": "anthropic", "kind": "skin", "group": "editorial", "name_cn": "奶油珊瑚", "oneliner": "奶油珊瑚 · AI 研究", "scenarios": ["AI", "产品", "研究分享", "人文品牌"], "mode": "light", "sample": "styles/_samples/anthropic.webp" },
|
|
21
|
+
{ "id": "hand-drawn", "kind": "skin", "group": "creative", "name_cn": "纸感手绘", "oneliner": "纸感手绘 · 创意教学", "scenarios": ["创意", "头脑风暴", "教学", "工作坊"], "mode": "light", "sample": "styles/_samples/hand-drawn.webp" },
|
|
22
|
+
{ "id": "cinereel", "kind": "skin", "group": "creative", "name_cn": "黑白胶片", "oneliner": "黑白胶片 · 影视创意", "scenarios": ["影视", "创意作品集", "音乐", "传媒"], "mode": "dark", "sample": "styles/_samples/cinereel.webp" },
|
|
23
|
+
{ "id": "branding", "kind": "skin", "group": "natural", "name_cn": "暖米绿意", "oneliner": "暖米绿意 · 品牌手册", "scenarios": ["品牌手册", "可持续", "美妆", "零售", "极简"], "mode": "light", "sample": "styles/_samples/branding.webp" }
|
|
24
|
+
]
|
|
25
|
+
}
|