@lemonppt/renderer 0.2.0 → 0.2.2

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 (72) hide show
  1. package/dist/client/client-render.js +65 -5401
  2. package/dist/client/editor-script.js +3355 -0
  3. package/dist/client/theme-echarts.js +65 -25
  4. package/dist/client-render.d.ts +1 -7
  5. package/dist/client-render.d.ts.map +1 -1
  6. package/dist/client-render.js +1 -11
  7. package/dist/client-render.js.map +1 -1
  8. package/dist/editor-script.d.ts +1 -1
  9. package/dist/editor-script.d.ts.map +1 -1
  10. package/dist/editor-script.js +80 -77
  11. package/dist/editor-script.js.map +1 -1
  12. package/dist/export-pdf.js +1 -1
  13. package/dist/export-pdf.js.map +1 -1
  14. package/dist/export-pptx.d.ts +1132 -2
  15. package/dist/export-pptx.d.ts.map +1 -1
  16. package/dist/export-pptx.js +1208 -19525
  17. package/dist/export-pptx.js.map +1 -1
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/render-editor-data.d.ts +21 -0
  23. package/dist/render-editor-data.d.ts.map +1 -0
  24. package/dist/render-editor-data.js +1068 -0
  25. package/dist/render-editor-data.js.map +1 -0
  26. package/dist/render.d.ts +0 -2
  27. package/dist/render.d.ts.map +1 -1
  28. package/dist/render.js +7 -323
  29. package/dist/render.js.map +1 -1
  30. package/dist/theme01-pptx.d.ts +12 -0
  31. package/dist/theme01-pptx.d.ts.map +1 -0
  32. package/dist/theme01-pptx.js +2954 -0
  33. package/dist/theme01-pptx.js.map +1 -0
  34. package/dist/theme02-pptx.d.ts +5 -0
  35. package/dist/theme02-pptx.d.ts.map +1 -0
  36. package/dist/theme02-pptx.js +1063 -0
  37. package/dist/theme02-pptx.js.map +1 -0
  38. package/dist/theme03-pptx.d.ts +5 -0
  39. package/dist/theme03-pptx.d.ts.map +1 -0
  40. package/dist/theme03-pptx.js +3279 -0
  41. package/dist/theme03-pptx.js.map +1 -0
  42. package/dist/theme04-pptx.d.ts +6 -0
  43. package/dist/theme04-pptx.d.ts.map +1 -0
  44. package/dist/theme04-pptx.js +5496 -0
  45. package/dist/theme04-pptx.js.map +1 -0
  46. package/dist/theme05-pptx.d.ts +5 -0
  47. package/dist/theme05-pptx.d.ts.map +1 -0
  48. package/dist/theme05-pptx.js +3152 -0
  49. package/dist/theme05-pptx.js.map +1 -0
  50. package/dist/theme06-pptx.d.ts +124 -0
  51. package/dist/theme06-pptx.d.ts.map +1 -0
  52. package/dist/theme06-pptx.js +8154 -0
  53. package/dist/theme06-pptx.js.map +1 -0
  54. package/dist/theme07-pptx.d.ts +49 -0
  55. package/dist/theme07-pptx.d.ts.map +1 -0
  56. package/dist/theme07-pptx.js +2579 -0
  57. package/dist/theme07-pptx.js.map +1 -0
  58. package/dist/theme08-pptx.d.ts +19 -0
  59. package/dist/theme08-pptx.d.ts.map +1 -0
  60. package/dist/theme08-pptx.js +1411 -0
  61. package/dist/theme08-pptx.js.map +1 -0
  62. package/dist/theme09-pptx.d.ts +18 -0
  63. package/dist/theme09-pptx.d.ts.map +1 -0
  64. package/dist/theme09-pptx.js +1513 -0
  65. package/dist/theme09-pptx.js.map +1 -0
  66. package/dist/theme10-pptx.d.ts +18 -0
  67. package/dist/theme10-pptx.d.ts.map +1 -0
  68. package/dist/theme10-pptx.js +2889 -0
  69. package/dist/theme10-pptx.js.map +1 -0
  70. package/package.json +7 -6
  71. package/templates/editor.html +580 -0
  72. package/templates/editor.js +222 -0
@@ -0,0 +1,2579 @@
1
+ // lemonPPT - AI-powered presentation generation
2
+ // Copyright (c) 2026 lemonforme
3
+ // SPDX-License-Identifier: AGPL-3.0-or-later
4
+ //
5
+ // theme07 PPTX 版式专属渲染器(从 export-pptx.ts 抽出)。
6
+ // 共享基础设施(全局 helper + 通用渲染器 + 类型 + theme07 局部 helper/const)从 export-pptx.ts 导入;
7
+ // theme01 通用渲染器从 theme01-pptx.ts 复用;其他已抽出主题的渲染器从各自 theme<K>-pptx.ts 复用。
8
+ // 注册通过 registerTheme07Renderers 回调注入。
9
+ import { addTheme07Kicker, FONTS, COLORS, addTheme07Card, addImageMaybe, addTheme07GlowLine, addTheme07Footer, resolveTheme07CssColor, getLayoutCoordinates } from './export-pptx.js';
10
+ export function renderTheme07CoverV1(slide, props) {
11
+ if (props.tag) {
12
+ addTheme07Kicker(slide, props.tag, 0.65, 0.55);
13
+ }
14
+ slide.addText(props.title ?? '', {
15
+ x: 0.65, y: 0.95, w: 4.7, h: 1.6,
16
+ fontSize: 46, bold: true, fontFace: FONTS.heading, color: COLORS.primary,
17
+ valign: 'top',
18
+ });
19
+ if (props.subtitle) {
20
+ slide.addText(props.subtitle, {
21
+ x: 0.65, y: 2.65, w: 4.7, h: 0.6,
22
+ fontSize: 15, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
23
+ });
24
+ }
25
+ // 底部标签
26
+ if (props.tags && props.tags.length > 0) {
27
+ const tags = props.tags.map((t) => typeof t === 'string' ? t : t.item).filter(Boolean);
28
+ let tagX = 0.65;
29
+ tags.slice(0, 6).forEach((tag) => {
30
+ const w = Math.min(2.0, 0.25 + tag.length * 0.12);
31
+ addTheme07Card(slide, tagX, 3.55, w, 0.32, 0.04, COLORS.white);
32
+ slide.addText(tag, {
33
+ x: tagX + 0.05, y: 3.6, w: w - 0.1, h: 0.22,
34
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center',
35
+ });
36
+ tagX += w + 0.12;
37
+ });
38
+ }
39
+ // 右侧图片区
40
+ if (props.imageUrl) {
41
+ addImageMaybe(slide, props.imageUrl, 5.6, 0.85, 3.75, 2.3);
42
+ }
43
+ else {
44
+ addTheme07Card(slide, 5.6, 0.85, 3.75, 2.3, 0.08, COLORS.white);
45
+ }
46
+ // 右侧数据指标
47
+ if (props.metrics && props.metrics.length > 0) {
48
+ const metricY = 3.35;
49
+ const metricW = 3.75 / Math.min(props.metrics.length, 4);
50
+ props.metrics.slice(0, 4).forEach((m, idx) => {
51
+ const x = 5.6 + idx * metricW;
52
+ addTheme07Card(slide, x, metricY, metricW - 0.08, 0.9, 0.06, COLORS.white);
53
+ slide.addText(`${m.value ?? ''}${m.unit ?? ''}`, {
54
+ x, y: metricY + 0.12, w: metricW - 0.08, h: 0.35,
55
+ fontSize: 20, color: m.accent ? COLORS.accent : COLORS.primary, bold: true, fontFace: FONTS.heading,
56
+ });
57
+ if (m.label) {
58
+ slide.addText(m.label, {
59
+ x, y: metricY + 0.48, w: metricW - 0.08, h: 0.2,
60
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono,
61
+ });
62
+ }
63
+ });
64
+ }
65
+ addTheme07GlowLine(slide);
66
+ addTheme07Footer(slide, props);
67
+ }
68
+ export function renderTheme07TableOfContentsV1(slide, props) {
69
+ if (props.kicker) {
70
+ addTheme07Kicker(slide, props.kicker);
71
+ }
72
+ slide.addText(props.title ?? '', {
73
+ x: 0.65, y: 0.9, w: 8.7, h: 0.7,
74
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
75
+ });
76
+ if (props.subtitle) {
77
+ slide.addText(props.subtitle, {
78
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
79
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
80
+ });
81
+ }
82
+ slide.addShape('line', {
83
+ x1: 0.65, y1: 2.2, x2: 1.5, y2: 2.2,
84
+ line: { color: COLORS.accent, width: 3 },
85
+ });
86
+ if (props.entries && props.entries.length > 0) {
87
+ const colW = 4.2;
88
+ const rowH = 0.65;
89
+ const startY = 2.5;
90
+ props.entries.slice(0, 8).forEach((entry, idx) => {
91
+ const col = idx % 2;
92
+ const row = Math.floor(idx / 2);
93
+ const x = 0.65 + col * (colW + 0.3);
94
+ const y = startY + row * rowH;
95
+ const fill = entry.accent ? COLORS.accent : COLORS.white;
96
+ addTheme07Card(slide, x, y, colW, rowH - 0.1, 0.08, fill);
97
+ const numColor = entry.accent ? COLORS.white : COLORS.accent;
98
+ const textColor = entry.accent ? COLORS.white : COLORS.primary;
99
+ const pageColor = entry.accent ? COLORS.white : COLORS.secondary;
100
+ slide.addText(entry.number ?? '', {
101
+ x: x + 0.15, y: y + 0.1, w: 0.6, h: 0.35,
102
+ fontSize: 20, color: numColor, bold: true, fontFace: FONTS.heading,
103
+ });
104
+ slide.addText(entry.title ?? '', {
105
+ x: x + 0.8, y: y + 0.13, w: colW - 1.4, h: 0.3,
106
+ fontSize: 13, color: textColor, fontFace: FONTS.body,
107
+ });
108
+ if (entry.page) {
109
+ slide.addText(entry.page, {
110
+ x: x + colW - 0.65, y: y + 0.13, w: 0.5, h: 0.3,
111
+ fontSize: 10, color: pageColor, fontFace: FONTS.mono, align: 'right',
112
+ });
113
+ }
114
+ });
115
+ }
116
+ if (props.footnote) {
117
+ slide.addText(props.footnote, {
118
+ x: 0.65, y: 4.95, w: 8.7, h: 0.3,
119
+ fontSize: 11, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
120
+ });
121
+ }
122
+ addTheme07GlowLine(slide);
123
+ }
124
+ export function renderTheme07ChapterV1(slide, props) {
125
+ // 深色背景块
126
+ slide.addShape('rect', {
127
+ x: 0, y: 0, w: 10, h: 5.625,
128
+ fill: { color: '11161D' },
129
+ });
130
+ // 超大章节号
131
+ slide.addText(props.number ?? '', {
132
+ x: 0.65, y: 0.9, w: 3.5, h: 2.0,
133
+ fontSize: 110, color: COLORS.accent, bold: true, fontFace: FONTS.heading, valign: 'top',
134
+ });
135
+ slide.addText(props.title ?? '', {
136
+ x: 0.65, y: 2.9, w: 8.7, h: 0.85,
137
+ fontSize: 42, bold: true, fontFace: FONTS.heading, color: COLORS.white, valign: 'top',
138
+ });
139
+ if (props.subtitle) {
140
+ slide.addText(props.subtitle, {
141
+ x: 0.65, y: 3.75, w: 8.7, h: 0.35,
142
+ fontSize: 15, color: 'D0D4DC', fontFace: FONTS.body, valign: 'top',
143
+ });
144
+ }
145
+ if (props.enSubtitle) {
146
+ slide.addText(props.enSubtitle, {
147
+ x: 0.65, y: 4.15, w: 8.7, h: 0.25,
148
+ fontSize: 10, color: '8B93A3', fontFace: FONTS.mono, valign: 'top',
149
+ });
150
+ }
151
+ if (props.tags && props.tags.length > 0) {
152
+ const tagY = 4.7;
153
+ let tagX = 0.65;
154
+ const tags = props.tags.map((t) => typeof t === 'string' ? t : t.item).filter(Boolean);
155
+ tags.slice(0, 6).forEach((tag) => {
156
+ const w = Math.min(2.2, 0.3 + tag.length * 0.12);
157
+ slide.addShape('roundRect', {
158
+ x: tagX, y: tagY, w, h: 0.32,
159
+ fill: { color: '1A2330' },
160
+ line: { color: '3A4559', width: 1 },
161
+ rectRadius: 0.04,
162
+ });
163
+ slide.addText(tag, {
164
+ x: tagX + 0.05, y: tagY + 0.05, w: w - 0.1, h: 0.22,
165
+ fontSize: 10, color: 'D0D4DC', fontFace: FONTS.mono, align: 'center',
166
+ });
167
+ tagX += w + 0.15;
168
+ });
169
+ }
170
+ }
171
+ export function renderTheme07ContentV1(slide, props) {
172
+ if (props.imageUrl) {
173
+ addImageMaybe(slide, props.imageUrl, 0, 0, 10, 5.625);
174
+ }
175
+ if (props.kicker) {
176
+ addTheme07Kicker(slide, props.kicker);
177
+ }
178
+ slide.addText(props.title ?? '', {
179
+ x: 0.65, y: 0.95, w: 4.7, h: 0.8,
180
+ fontSize: 32, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
181
+ });
182
+ if (props.subtitle) {
183
+ slide.addText(props.subtitle, {
184
+ x: 0.65, y: 1.75, w: 4.7, h: 0.5,
185
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
186
+ });
187
+ }
188
+ slide.addShape('line', {
189
+ x1: 0.65, y1: 2.3, x2: 1.5, y2: 2.3,
190
+ line: { color: COLORS.accent, width: 3 },
191
+ });
192
+ if (props.showConclusion !== false && props.conclusion) {
193
+ const c = props.conclusion;
194
+ addTheme07Card(slide, 0.65, 2.55, 4.7, 1.5, 0.08, COLORS.white);
195
+ slide.addShape('rect', {
196
+ x: 0.65, y: 2.55, w: 0.06, h: 1.5,
197
+ fill: { color: COLORS.accent },
198
+ });
199
+ if (c.value) {
200
+ slide.addText(c.value, {
201
+ x: 0.85, y: 2.7, w: 4.3, h: 0.5,
202
+ fontSize: 32, color: COLORS.accent, bold: true, fontFace: FONTS.heading,
203
+ });
204
+ }
205
+ if (c.label) {
206
+ slide.addText(c.label, {
207
+ x: 0.85, y: 3.2, w: 4.3, h: 0.25,
208
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono,
209
+ });
210
+ }
211
+ if (c.description) {
212
+ slide.addText(c.description, {
213
+ x: 0.85, y: 3.5, w: 4.3, h: 0.5,
214
+ fontSize: 11, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
215
+ });
216
+ }
217
+ }
218
+ if (props.items && props.items.length > 0) {
219
+ const startY = 0.95;
220
+ const itemH = 0.75;
221
+ props.items.slice(0, 6).forEach((item, idx) => {
222
+ const y = startY + idx * itemH;
223
+ addTheme07Card(slide, 5.6, y, 3.75, itemH - 0.1, 0.08, COLORS.white);
224
+ slide.addText(String(idx + 1).padStart(2, '0'), {
225
+ x: 5.75, y: y + 0.1, w: 0.5, h: 0.35,
226
+ fontSize: 20, color: COLORS.accent, bold: true, fontFace: FONTS.heading,
227
+ });
228
+ if (item.title) {
229
+ slide.addText(item.title, {
230
+ x: 6.35, y: y + 0.1, w: 2.85, h: 0.3,
231
+ fontSize: 13, color: COLORS.primary, bold: true, fontFace: FONTS.body,
232
+ });
233
+ }
234
+ if (item.desc) {
235
+ slide.addText(item.desc, {
236
+ x: 6.35, y: y + 0.4, w: 2.85, h: 0.25,
237
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
238
+ });
239
+ }
240
+ });
241
+ }
242
+ }
243
+ export function renderTheme07SummaryV1(slide, props) {
244
+ if (props.kicker) {
245
+ addTheme07Kicker(slide, props.kicker);
246
+ }
247
+ slide.addText(props.title ?? '', {
248
+ x: 0.65, y: 0.95, w: 4.7, h: 0.7,
249
+ fontSize: 32, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
250
+ });
251
+ if (props.subtitle) {
252
+ slide.addText(props.subtitle, {
253
+ x: 0.65, y: 1.7, w: 4.7, h: 0.4,
254
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
255
+ });
256
+ }
257
+ slide.addShape('line', {
258
+ x1: 0.65, y1: 2.2, x2: 1.5, y2: 2.2,
259
+ line: { color: COLORS.accent, width: 3 },
260
+ });
261
+ if (props.points && props.points.length > 0) {
262
+ const startY = 2.5;
263
+ const pointH = 0.55;
264
+ props.points.slice(0, 6).forEach((p, idx) => {
265
+ const text = typeof p === 'string' ? p : p.text;
266
+ const y = startY + idx * pointH;
267
+ slide.addShape('ellipse', {
268
+ x: 0.7, y: y + 0.1, w: 0.1, h: 0.1,
269
+ fill: { color: COLORS.accent },
270
+ });
271
+ slide.addText(text ?? '', {
272
+ x: 0.95, y: y, w: 4.4, h: 0.5,
273
+ fontSize: 13, color: COLORS.primary, fontFace: FONTS.body, valign: 'top',
274
+ });
275
+ });
276
+ }
277
+ // 右侧指标卡
278
+ if (props.metrics && props.metrics.length > 0) {
279
+ const cardW = 1.78;
280
+ const cardH = 0.85;
281
+ props.metrics.slice(0, 4).forEach((m, idx) => {
282
+ const col = idx % 2;
283
+ const row = Math.floor(idx / 2);
284
+ const x = 5.6 + col * (cardW + 0.12);
285
+ const y = 0.95 + row * (cardH + 0.12);
286
+ addTheme07Card(slide, x, y, cardW, cardH, 0.06, COLORS.white);
287
+ slide.addText(m.value ?? '', {
288
+ x: x + 0.1, y: y + 0.1, w: cardW - 0.2, h: 0.35,
289
+ fontSize: 22, color: COLORS.accent, bold: true, fontFace: FONTS.heading,
290
+ });
291
+ slide.addText(m.label ?? '', {
292
+ x: x + 0.1, y: y + 0.48, w: cardW - 0.2, h: 0.25,
293
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono,
294
+ });
295
+ });
296
+ }
297
+ // 右侧结论面板
298
+ if (props.conclusion) {
299
+ addTheme07Card(slide, 5.6, 2.95, 3.75, 1.9, 0.08, COLORS.white);
300
+ slide.addShape('rect', {
301
+ x: 5.6, y: 2.95, w: 0.06, h: 1.9,
302
+ fill: { color: COLORS.accent },
303
+ });
304
+ slide.addText('CONCLUSION', {
305
+ x: 5.85, y: 3.1, w: 3.3, h: 0.3,
306
+ fontSize: 11, color: COLORS.accent, bold: true, fontFace: FONTS.mono, charSpacing: 2,
307
+ });
308
+ slide.addText(props.conclusion, {
309
+ x: 5.85, y: 3.45, w: 3.3, h: 1.3,
310
+ fontSize: 17, color: COLORS.primary, bold: true, fontFace: FONTS.heading, valign: 'top',
311
+ });
312
+ }
313
+ if (props.footnote) {
314
+ slide.addText(props.footnote, {
315
+ x: 0.65, y: 4.95, w: 8.7, h: 0.3,
316
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
317
+ });
318
+ }
319
+ addTheme07GlowLine(slide);
320
+ }
321
+ export function renderTheme07RankingV1(slide, props) {
322
+ if (props.kicker) {
323
+ addTheme07Kicker(slide, props.kicker);
324
+ }
325
+ slide.addText(props.title ?? '', {
326
+ x: 0.65, y: 0.9, w: 8.7, h: 0.7,
327
+ fontSize: 32, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
328
+ });
329
+ if (props.subtitle) {
330
+ slide.addText(props.subtitle, {
331
+ x: 0.65, y: 1.6, w: 8.7, h: 0.4,
332
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
333
+ });
334
+ }
335
+ slide.addShape('line', {
336
+ x1: 0.65, y1: 2.1, x2: 1.5, y2: 2.1,
337
+ line: { color: COLORS.accent, width: 3 },
338
+ });
339
+ if (props.entries && props.entries.length > 0) {
340
+ const startY = 2.35;
341
+ const rowH = 0.48;
342
+ const maxValue = Math.max(1, ...props.entries.map((e) => parseFloat(e.value) || 0));
343
+ props.entries.slice(0, 10).forEach((entry, idx) => {
344
+ const y = startY + idx * rowH;
345
+ const isAccent = entry.accent === true;
346
+ const progress = entry.progress ?? Math.round(((parseFloat(entry.value) || 0) / maxValue) * 100);
347
+ if (isAccent) {
348
+ slide.addShape('roundRect', {
349
+ x: 0.65, y, w: 8.7, h: rowH - 0.06,
350
+ fill: { color: COLORS.accent },
351
+ rectRadius: 0.06,
352
+ });
353
+ }
354
+ else {
355
+ addTheme07Card(slide, 0.65, y, 8.7, rowH - 0.06, 0.06, COLORS.white);
356
+ }
357
+ const numColor = isAccent ? COLORS.white : COLORS.accent;
358
+ const textColor = isAccent ? COLORS.white : COLORS.primary;
359
+ const subColor = isAccent ? COLORS.white : COLORS.secondary;
360
+ slide.addText(String(idx + 1).padStart(2, '0'), {
361
+ x: 0.8, y: y + 0.06, w: 0.55, h: 0.3,
362
+ fontSize: 17, color: numColor, bold: true, fontFace: FONTS.heading,
363
+ });
364
+ slide.addText(entry.name ?? '', {
365
+ x: 1.45, y: y + 0.08, w: 4.5, h: 0.3,
366
+ fontSize: 14, color: textColor, bold: true, fontFace: FONTS.body,
367
+ });
368
+ if (entry.note) {
369
+ slide.addText(entry.note, {
370
+ x: 1.45, y: y + 0.28, w: 4.5, h: 0.15,
371
+ fontSize: 9, color: subColor, fontFace: FONTS.mono,
372
+ });
373
+ }
374
+ // 进度条背景
375
+ slide.addShape('roundRect', {
376
+ x: 5.8, y: y + 0.14, w: 2.4, h: 0.08,
377
+ fill: { color: isAccent ? '5A7FA8' : 'E5E8ED' },
378
+ rectRadius: 0.04,
379
+ });
380
+ // 进度条填充
381
+ if (progress > 0) {
382
+ slide.addShape('roundRect', {
383
+ x: 5.8, y: y + 0.14, w: 2.4 * (progress / 100), h: 0.08,
384
+ fill: { color: isAccent ? COLORS.white : COLORS.accent },
385
+ rectRadius: 0.04,
386
+ });
387
+ }
388
+ slide.addText(`${entry.value ?? ''}${props.unit ?? ''}`, {
389
+ x: 8.3, y: y + 0.04, w: 0.9, h: 0.3,
390
+ fontSize: 15, color: isAccent ? COLORS.white : COLORS.accent, bold: true, fontFace: FONTS.mono, align: 'right',
391
+ });
392
+ });
393
+ }
394
+ if (props.legend && props.legend.length > 0) {
395
+ let lx = 0.65;
396
+ props.legend.slice(0, 4).forEach((item) => {
397
+ slide.addShape('rect', {
398
+ x: lx, y: 4.85, w: 0.12, h: 0.12,
399
+ fill: { color: resolveTheme07CssColor(item.color) },
400
+ });
401
+ slide.addText(item.label ?? '', {
402
+ x: lx + 0.2, y: 4.82, w: 1.6, h: 0.2,
403
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono,
404
+ });
405
+ lx += 1.8;
406
+ });
407
+ }
408
+ if (props.footnote) {
409
+ slide.addText(props.footnote, {
410
+ x: 0.65, y: 5.15, w: 8.7, h: 0.25,
411
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
412
+ });
413
+ }
414
+ addTheme07GlowLine(slide);
415
+ }
416
+ export function renderTheme07CaseV1(slide, props) {
417
+ if (props.imageUrl) {
418
+ addImageMaybe(slide, props.imageUrl, 0, 0, 10, 5.625);
419
+ }
420
+ if (props.kicker) {
421
+ addTheme07Kicker(slide, props.kicker);
422
+ }
423
+ slide.addText(props.title ?? '', {
424
+ x: 0.65, y: 0.95, w: 4.7, h: 0.6,
425
+ fontSize: 28, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
426
+ });
427
+ if (props.subtitle) {
428
+ slide.addText(props.subtitle, {
429
+ x: 0.65, y: 1.55, w: 4.7, h: 0.3,
430
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
431
+ });
432
+ }
433
+ if (props.description) {
434
+ slide.addText(props.description, {
435
+ x: 0.65, y: 1.95, w: 4.7, h: 0.6,
436
+ fontSize: 12, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
437
+ });
438
+ }
439
+ // 案例卡片
440
+ if (props.cards && props.cards.length > 0) {
441
+ const cardW = 2.85;
442
+ const cardH = 3.3;
443
+ const startY = 0.95;
444
+ props.cards.slice(0, 3).forEach((card, idx) => {
445
+ const x = 5.6 + idx * (cardW + 0.15);
446
+ const fill = card.accent ? COLORS.accent : COLORS.white;
447
+ addTheme07Card(slide, x, startY, cardW, cardH, 0.08, fill);
448
+ const textColor = card.accent ? COLORS.white : COLORS.primary;
449
+ const subColor = card.accent ? 'D0E0F0' : COLORS.secondary;
450
+ // 卡片顶部图片区域(DROP MEDIA 占位)
451
+ const imgAreaH = 1.35;
452
+ const imgFill = card.accent ? '#E8F0E8' : '#F0F4EF';
453
+ slide.addShape('roundRect', {
454
+ x: x + 0.08, y: startY + 0.08, w: cardW - 0.16, h: imgAreaH - 0.06,
455
+ fill: { color: imgFill }, rectRadius: 0.06,
456
+ line: { color: card.accent ? '#B8CCB8' : '#D8E8D8', width: 0.5 },
457
+ });
458
+ if (card.imageUrl) {
459
+ addImageMaybe(slide, card.imageUrl, x + 0.1, startY + 0.1, cardW - 0.2, imgAreaH - 0.1);
460
+ }
461
+ else {
462
+ // DROP MEDIA 文字
463
+ if (card.accent) {
464
+ slide.addShape('roundRect', {
465
+ x: x + 0.15, y: startY + 0.15, w: 0.55, h: 0.22,
466
+ fill: { color: '#7B9E7B' }, rectRadius: 0.11,
467
+ });
468
+ slide.addText('重点', {
469
+ x: x + 0.15, y: startY + 0.16, w: 0.55, h: 0.2,
470
+ fontSize: 8, color: COLORS.white, bold: true, fontFace: FONTS.mono, align: 'center',
471
+ });
472
+ }
473
+ slide.addText('DROP MEDIA', {
474
+ x: x, y: startY + imgAreaH * 0.48, w: cardW, h: 0.22,
475
+ fontSize: 9, color: '#A0C0A0', fontFace: FONTS.mono, align: 'center', charSpacing: 1.5,
476
+ });
477
+ if (card.company) {
478
+ slide.addText(card.company, {
479
+ x: x + 0.12, y: startY + imgAreaH - 0.32, w: cardW - 0.24, h: 0.22,
480
+ fontSize: 11, bold: true, fontFace: FONTS.heading, color: subColor,
481
+ });
482
+ }
483
+ }
484
+ // 卡片内容从图片区域下方开始
485
+ const contentStartY = startY + imgAreaH + 0.05;
486
+ slide.addText(`案例 ${String(idx + 1).padStart(2, '0')}`, {
487
+ x: x + 0.15, y: contentStartY, w: cardW - 0.3, h: 0.25,
488
+ fontSize: 10, color: card.accent ? COLORS.white : COLORS.accent, bold: true, fontFace: FONTS.mono, charSpacing: 2,
489
+ });
490
+ if (card.company) {
491
+ slide.addText(card.company, {
492
+ x: x + 0.15, y: contentStartY + 0.3, w: cardW - 0.3, h: 0.4,
493
+ fontSize: 20, color: textColor, bold: true, fontFace: FONTS.heading,
494
+ });
495
+ }
496
+ if (card.tagline) {
497
+ slide.addText(card.tagline, {
498
+ x: x + 0.15, y: contentStartY + 0.7, w: cardW - 0.3, h: 0.28,
499
+ fontSize: 11, color: subColor, fontFace: FONTS.body, valign: 'top',
500
+ });
501
+ }
502
+ const tags = (card.tags || []).map((t) => typeof t === 'string' ? t : t.item).filter(Boolean);
503
+ if (tags.length > 0) {
504
+ let tx = x + 0.15;
505
+ tags.slice(0, 4).forEach((tag) => {
506
+ const tw = 0.25 + tag.length * 0.11;
507
+ slide.addShape('roundRect', {
508
+ x: tx, y: contentStartY + 1.02, w: tw, h: 0.26,
509
+ fill: { color: card.accent ? '3A6A99' : COLORS.surface },
510
+ rectRadius: 0.04,
511
+ });
512
+ slide.addText(tag, {
513
+ x: tx + 0.03, y: contentStartY + 1.04, w: tw - 0.06, h: 0.22,
514
+ fontSize: 9, color: card.accent ? COLORS.white : COLORS.secondary, fontFace: FONTS.mono, align: 'center',
515
+ });
516
+ tx += tw + 0.06;
517
+ });
518
+ }
519
+ if (card.metricValue || card.metricLabel) {
520
+ slide.addShape('line', {
521
+ x1: x + 0.15, y1: startY + cardH - 0.85, x2: x + cardW - 0.15, y2: startY + cardH - 0.85,
522
+ line: { color: card.accent ? '5A7FA8' : COLORS.border, width: 1 },
523
+ });
524
+ slide.addText(card.metricValue ?? '', {
525
+ x: x + 0.15, y: startY + cardH - 0.75, w: cardW - 0.3, h: 0.4,
526
+ fontSize: 24, color: card.accent ? COLORS.white : COLORS.accent, bold: true, fontFace: FONTS.heading,
527
+ });
528
+ slide.addText(card.metricLabel ?? '', {
529
+ x: x + 0.15, y: startY + cardH - 0.35, w: cardW - 0.3, h: 0.25,
530
+ fontSize: 9, color: subColor, fontFace: FONTS.mono,
531
+ });
532
+ }
533
+ });
534
+ }
535
+ if (props.footnote) {
536
+ slide.addText(props.footnote, {
537
+ x: 0.65, y: 4.95, w: 8.7, h: 0.3,
538
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
539
+ });
540
+ }
541
+ addTheme07GlowLine(slide);
542
+ }
543
+ export function renderTheme07SourcesV1(slide, props) {
544
+ if (props.kicker) {
545
+ addTheme07Kicker(slide, props.kicker);
546
+ }
547
+ slide.addText(props.title ?? '', {
548
+ x: 0.65, y: 0.9, w: 7.2, h: 0.7,
549
+ fontSize: 32, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
550
+ });
551
+ if (props.sampleSize?.value) {
552
+ slide.addText(props.sampleSize.value, {
553
+ x: 8.1, y: 0.85, w: 1.25, h: 0.5,
554
+ fontSize: 40, color: COLORS.accent, bold: true, fontFace: FONTS.heading, align: 'right',
555
+ });
556
+ slide.addText(props.sampleSize.label ?? '', {
557
+ x: 7.6, y: 1.35, w: 1.75, h: 0.3,
558
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono, align: 'right',
559
+ });
560
+ }
561
+ if (props.subtitle) {
562
+ slide.addText(props.subtitle, {
563
+ x: 0.65, y: 1.6, w: 8.7, h: 0.4,
564
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
565
+ });
566
+ }
567
+ slide.addShape('line', {
568
+ x1: 0.65, y1: 2.1, x2: 1.5, y2: 2.1,
569
+ line: { color: COLORS.accent, width: 3 },
570
+ });
571
+ if (props.entries && props.entries.length > 0) {
572
+ const colW = 4.2;
573
+ const rowH = 0.65;
574
+ const startY = 2.35;
575
+ props.entries.slice(0, 16).forEach((entry, idx) => {
576
+ const col = idx % 2;
577
+ const row = Math.floor(idx / 2);
578
+ const x = 0.65 + col * (colW + 0.3);
579
+ const y = startY + row * rowH;
580
+ addTheme07Card(slide, x, y, colW, rowH - 0.08, 0.06, COLORS.white);
581
+ slide.addText(String(idx + 1).padStart(2, '0'), {
582
+ x: x + 0.15, y: y + 0.08, w: 0.45, h: 0.3,
583
+ fontSize: 12, color: COLORS.accent, bold: true, fontFace: FONTS.mono,
584
+ });
585
+ slide.addText(entry.name ?? '', {
586
+ x: x + 0.65, y: y + 0.05, w: colW - 0.8, h: 0.25,
587
+ fontSize: 12, color: COLORS.primary, bold: true, fontFace: FONTS.heading,
588
+ });
589
+ if (entry.note) {
590
+ slide.addText(entry.note, {
591
+ x: x + 0.65, y: y + 0.28, w: colW - 0.8, h: 0.18,
592
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.body,
593
+ });
594
+ }
595
+ if (typeof entry.confidence === 'number') {
596
+ const pct = Math.max(0, Math.min(100, entry.confidence));
597
+ slide.addShape('roundRect', {
598
+ x: x + colW - 1.05, y: y + 0.38, w: 0.9, h: 0.08,
599
+ fill: { color: 'E5E8ED' },
600
+ rectRadius: 0.04,
601
+ });
602
+ slide.addShape('roundRect', {
603
+ x: x + colW - 1.05, y: y + 0.38, w: 0.9 * (pct / 100), h: 0.08,
604
+ fill: { color: COLORS.accent2 },
605
+ rectRadius: 0.04,
606
+ });
607
+ slide.addText(`${pct}/100`, {
608
+ x: x + colW - 1.05, y: y + 0.46, w: 0.9, h: 0.15,
609
+ fontSize: 8, color: COLORS.secondary, fontFace: FONTS.mono, align: 'right',
610
+ });
611
+ }
612
+ });
613
+ }
614
+ // 处理流程
615
+ if (props.process && props.process.length > 0) {
616
+ const steps = props.process.map((p) => typeof p === 'string' ? p : p.item).filter(Boolean);
617
+ let px = 0.65;
618
+ steps.slice(0, 6).forEach((step, idx) => {
619
+ const pw = 0.45 + step.length * 0.12;
620
+ slide.addShape('roundRect', {
621
+ x: px, y: 4.55, w: pw, h: 0.32,
622
+ fill: { color: COLORS.white },
623
+ line: { color: COLORS.border, width: 1 },
624
+ rectRadius: 0.04,
625
+ });
626
+ slide.addText(`${String(idx + 1).padStart(2, '0')} ${step}`, {
627
+ x: px + 0.05, y: 4.58, w: pw - 0.1, h: 0.26,
628
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center',
629
+ });
630
+ px += pw + 0.2;
631
+ if (idx < steps.length - 1) {
632
+ slide.addText('→', {
633
+ x: px - 0.16, y: 4.55, w: 0.12, h: 0.32,
634
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center',
635
+ });
636
+ }
637
+ });
638
+ }
639
+ if (props.footnote) {
640
+ slide.addShape('line', {
641
+ x1: 0.65, y1: 4.9, x2: 9.35, y2: 4.9,
642
+ line: { color: COLORS.border, width: 1 },
643
+ });
644
+ slide.addText(props.footnote, {
645
+ x: 0.65, y: 5.0, w: 8.7, h: 0.35,
646
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
647
+ });
648
+ }
649
+ addTheme07GlowLine(slide);
650
+ }
651
+ export function renderTheme07ChapterCapitalV1(slide, props) {
652
+ renderTheme07ChapterV1(slide, props);
653
+ }
654
+ export function renderTheme07ChapterRiskV1(slide, props) {
655
+ renderTheme07ChapterV1(slide, props);
656
+ }
657
+ export function renderTheme07ChapterAppendixV1(slide, props) {
658
+ renderTheme07ChapterV1(slide, props);
659
+ }
660
+ export function renderTheme07MethodV1(slide, props) {
661
+ if (props.kicker) {
662
+ addTheme07Kicker(slide, props.kicker);
663
+ }
664
+ slide.addText(props.title ?? '', {
665
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
666
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
667
+ });
668
+ if (props.subtitle) {
669
+ slide.addText(props.subtitle, {
670
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
671
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
672
+ });
673
+ }
674
+ slide.addShape('line', {
675
+ x1: 0.65, y1: 2.15, x2: 1.5, y2: 2.15,
676
+ line: { color: COLORS.accent, width: 3 },
677
+ });
678
+ const steps = (props.steps || []).slice(0, 4);
679
+ if (steps.length > 0) {
680
+ const cardW = 8.7 / steps.length;
681
+ const gap = 0.14;
682
+ const usableW = cardW - gap;
683
+ steps.forEach((step, idx) => {
684
+ const x = 0.65 + idx * cardW;
685
+ const y = 2.45;
686
+ addTheme07Card(slide, x, y, usableW, 2.55, 0.08, COLORS.white);
687
+ const num = (step.number || String(idx + 1).padStart(2, '0'));
688
+ slide.addText(num, {
689
+ x: x + 0.12, y: y + 0.12, w: usableW - 0.24, h: 0.4,
690
+ fontSize: 24, color: COLORS.accent, bold: true, fontFace: FONTS.heading,
691
+ });
692
+ if (step.title) {
693
+ slide.addText(step.title, {
694
+ x: x + 0.12, y: y + 0.62, w: usableW - 0.24, h: 0.35,
695
+ fontSize: 14, color: COLORS.primary, bold: true, fontFace: FONTS.body,
696
+ });
697
+ }
698
+ if (step.description) {
699
+ slide.addText(step.description, {
700
+ x: x + 0.12, y: y + 1.05, w: usableW - 0.24, h: 1.3,
701
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
702
+ });
703
+ }
704
+ if (idx < steps.length - 1) {
705
+ slide.addText('→', {
706
+ x: x + usableW + 0.02, y: y + 1.1, w: gap + 0.02, h: 0.3,
707
+ fontSize: 12, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center',
708
+ });
709
+ }
710
+ });
711
+ }
712
+ if (props.footnote) {
713
+ slide.addText(props.footnote, {
714
+ x: 0.65, y: 5.05, w: 8.7, h: 0.25,
715
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
716
+ });
717
+ }
718
+ addTheme07GlowLine(slide);
719
+ }
720
+ export function renderTheme07MonthlyV1(slide, props) {
721
+ if (props.kicker) {
722
+ addTheme07Kicker(slide, props.kicker);
723
+ }
724
+ slide.addText(props.title ?? '', {
725
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
726
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
727
+ });
728
+ if (props.subtitle) {
729
+ slide.addText(props.subtitle, {
730
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
731
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
732
+ });
733
+ }
734
+ const showConclusion = props.showConclusion !== false;
735
+ const hasConclusion = showConclusion && (props.conclusionValue || props.conclusionLabel || props.conclusionDescription);
736
+ const chartW = hasConclusion ? 5.6 : 8.7;
737
+ const labels = (props.labels || []).slice(0, 24).map((it) => (typeof it === 'string' ? it : it?.item ?? ''));
738
+ const series = (props.series || []).slice(0, 4);
739
+ if (labels.length >= 2 && series.length > 0) {
740
+ const chartData = series.map((s, idx) => {
741
+ const values = (s.data || []).map((d) => (typeof d === 'number' ? d : Number(d?.item ?? 0) || 0));
742
+ return {
743
+ name: s.name || `系列 ${idx + 1}`,
744
+ labels,
745
+ values,
746
+ };
747
+ });
748
+ slide.addChart('line', chartData, {
749
+ x: 0.65, y: 2.25, w: chartW, h: 3.0,
750
+ chartColors: ['2E5C8A', '7B9E7B', 'B8623E', '5B9BD5'],
751
+ lineDataSymbol: 'circle',
752
+ lineSmooth: true,
753
+ showLegend: series.length > 1,
754
+ showValue: false,
755
+ });
756
+ }
757
+ else {
758
+ slide.addText('(暂无趋势数据)', {
759
+ x: 0.65, y: 3.0, w: chartW, h: 0.6,
760
+ fontSize: 16, color: COLORS.secondary, align: 'center', valign: 'middle', fontFace: FONTS.body,
761
+ });
762
+ }
763
+ if (props.unit) {
764
+ addTheme07Card(slide, 6.45, 2.25, 2.9, 0.7, 0.08, COLORS.white);
765
+ slide.addText('单位', {
766
+ x: 6.6, y: 2.32, w: 2.6, h: 0.2,
767
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body,
768
+ });
769
+ slide.addText(props.unit, {
770
+ x: 6.6, y: 2.52, w: 2.6, h: 0.35,
771
+ fontSize: 18, color: COLORS.primary, bold: true, fontFace: FONTS.heading,
772
+ });
773
+ }
774
+ if (hasConclusion) {
775
+ const panelY = props.unit ? 3.05 : 2.25;
776
+ const panelH = props.unit ? 2.2 : 3.0;
777
+ addTheme07Card(slide, 6.45, panelY, 2.9, panelH, 0.08, COLORS.accent);
778
+ let cursorY = panelY + 0.18;
779
+ if (props.conclusionValue) {
780
+ slide.addText(props.conclusionValue, {
781
+ x: 6.65, y: cursorY, w: 2.5, h: 0.55,
782
+ fontSize: 32, color: COLORS.white, bold: true, fontFace: FONTS.heading,
783
+ });
784
+ cursorY += 0.58;
785
+ }
786
+ if (props.conclusionLabel) {
787
+ slide.addText(props.conclusionLabel, {
788
+ x: 6.65, y: cursorY, w: 2.5, h: 0.25,
789
+ fontSize: 10, color: 'FFFFFF', fontFace: FONTS.body,
790
+ });
791
+ cursorY += 0.32;
792
+ }
793
+ if (props.conclusionDescription) {
794
+ slide.addText(props.conclusionDescription, {
795
+ x: 6.65, y: cursorY, w: 2.5, h: panelH - (cursorY - panelY) - 0.25,
796
+ fontSize: 10, color: 'FFFFFF', valign: 'top', fontFace: FONTS.body,
797
+ });
798
+ }
799
+ }
800
+ addTheme07GlowLine(slide);
801
+ }
802
+ export function renderTheme07WaterfallV1(slide, props) {
803
+ if (props.kicker) {
804
+ addTheme07Kicker(slide, props.kicker);
805
+ }
806
+ slide.addText(props.title ?? '', {
807
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
808
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
809
+ });
810
+ if (props.subtitle) {
811
+ slide.addText(props.subtitle, {
812
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
813
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
814
+ });
815
+ }
816
+ const showConclusion = props.showConclusion !== false;
817
+ const hasConclusion = showConclusion && (props.conclusionValue || props.conclusionLabel || props.conclusionDescription);
818
+ const chartW = hasConclusion ? 5.6 : 8.7;
819
+ const labels = (props.labels || []).slice(0, 12).map((it) => (typeof it === 'string' ? it : it?.item ?? ''));
820
+ const values = (props.values || []).slice(0, 12).map((it) => (typeof it === 'number' ? it : Number(it?.item ?? 0) || 0));
821
+ if (labels.length >= 2 && values.length >= 2) {
822
+ let cumulative = 0;
823
+ const baseData = [];
824
+ const positiveData = [];
825
+ const negativeData = [];
826
+ values.forEach((v) => {
827
+ baseData.push(cumulative);
828
+ if (v >= 0) {
829
+ positiveData.push(v);
830
+ negativeData.push(0);
831
+ }
832
+ else {
833
+ positiveData.push(0);
834
+ negativeData.push(Math.abs(v));
835
+ }
836
+ cumulative += v;
837
+ });
838
+ slide.addChart('bar', [
839
+ { name: '基础', labels, values: baseData },
840
+ { name: '增加', labels, values: positiveData },
841
+ { name: '减少', labels, values: negativeData },
842
+ ], {
843
+ x: 0.65, y: 2.25, w: chartW, h: 3.0,
844
+ chartColors: [COLORS.surface, COLORS.accent2, COLORS.accentCool],
845
+ showValue: true,
846
+ dataLabelColor: COLORS.primary,
847
+ dataLabelFontSize: 9,
848
+ barGrouping: 'stacked',
849
+ barDir: 'col',
850
+ dataLabelPosition: 'outEnd',
851
+ });
852
+ }
853
+ else {
854
+ slide.addText('(暂无瀑布图数据)', {
855
+ x: 0.65, y: 3.0, w: chartW, h: 0.6,
856
+ fontSize: 16, color: COLORS.secondary, align: 'center', valign: 'middle', fontFace: FONTS.body,
857
+ });
858
+ }
859
+ if (props.unit) {
860
+ addTheme07Card(slide, 6.45, 2.25, 2.9, 0.7, 0.08, COLORS.white);
861
+ slide.addText('单位', {
862
+ x: 6.6, y: 2.32, w: 2.6, h: 0.2,
863
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body,
864
+ });
865
+ slide.addText(props.unit, {
866
+ x: 6.6, y: 2.52, w: 2.6, h: 0.35,
867
+ fontSize: 18, color: COLORS.primary, bold: true, fontFace: FONTS.heading,
868
+ });
869
+ }
870
+ if (hasConclusion) {
871
+ const panelY = props.unit ? 3.05 : 2.25;
872
+ const panelH = props.unit ? 2.2 : 3.0;
873
+ addTheme07Card(slide, 6.45, panelY, 2.9, panelH, 0.08, COLORS.accent);
874
+ let cursorY = panelY + 0.18;
875
+ if (props.conclusionValue) {
876
+ slide.addText(props.conclusionValue, {
877
+ x: 6.65, y: cursorY, w: 2.5, h: 0.55,
878
+ fontSize: 32, color: COLORS.white, bold: true, fontFace: FONTS.heading,
879
+ });
880
+ cursorY += 0.58;
881
+ }
882
+ if (props.conclusionLabel) {
883
+ slide.addText(props.conclusionLabel, {
884
+ x: 6.65, y: cursorY, w: 2.5, h: 0.25,
885
+ fontSize: 10, color: 'FFFFFF', fontFace: FONTS.body,
886
+ });
887
+ cursorY += 0.32;
888
+ }
889
+ if (props.conclusionDescription) {
890
+ slide.addText(props.conclusionDescription, {
891
+ x: 6.65, y: cursorY, w: 2.5, h: panelH - (cursorY - panelY) - 0.25,
892
+ fontSize: 10, color: 'FFFFFF', valign: 'top', fontFace: FONTS.body,
893
+ });
894
+ }
895
+ }
896
+ addTheme07GlowLine(slide);
897
+ }
898
+ export function renderTheme07MatrixV1(slide, props) {
899
+ if (props.kicker) {
900
+ addTheme07Kicker(slide, props.kicker);
901
+ }
902
+ slide.addText(props.title ?? '', {
903
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
904
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
905
+ });
906
+ if (props.subtitle) {
907
+ slide.addText(props.subtitle, {
908
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
909
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
910
+ });
911
+ }
912
+ if (props.xAxisLabel) {
913
+ slide.addText(props.xAxisLabel, {
914
+ x: 7.2, y: 5.15, w: 2.2, h: 0.25,
915
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono, align: 'right',
916
+ });
917
+ }
918
+ if (props.yAxisLabel) {
919
+ slide.addText(props.yAxisLabel, {
920
+ x: 0.65, y: 0.55, w: 1.5, h: 0.25,
921
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono,
922
+ });
923
+ }
924
+ const cells = (props.cells || []).slice(0, 4);
925
+ const focusIndex = Math.max(0, Math.min(3, Number(props.focusIndex ?? 0)));
926
+ if (cells.length === 4) {
927
+ const cellW = 4.2;
928
+ const cellH = 1.65;
929
+ const startX = 0.65;
930
+ const startY = 2.2;
931
+ cells.forEach((cell, idx) => {
932
+ const col = idx % 2;
933
+ const row = Math.floor(idx / 2);
934
+ const x = startX + col * (cellW + 0.18);
935
+ const y = startY + row * (cellH + 0.18);
936
+ const isFocus = cell.focus === true || idx === focusIndex;
937
+ addTheme07Card(slide, x, y, cellW, cellH, 0.08, isFocus ? COLORS.accent : COLORS.white);
938
+ const textColor = isFocus ? COLORS.white : COLORS.primary;
939
+ const subColor = isFocus ? 'D0E0F0' : COLORS.secondary;
940
+ if (cell.title) {
941
+ slide.addText(cell.title, {
942
+ x: x + 0.15, y: y + 0.12, w: cellW - 0.3, h: 0.35,
943
+ fontSize: 16, color: textColor, bold: true, fontFace: FONTS.heading,
944
+ });
945
+ }
946
+ if (cell.description) {
947
+ slide.addText(cell.description, {
948
+ x: x + 0.15, y: y + 0.55, w: cellW - 0.3, h: 0.95,
949
+ fontSize: 10, color: subColor, fontFace: FONTS.body, valign: 'top',
950
+ });
951
+ }
952
+ });
953
+ }
954
+ // 轴线(与 HTML 十字轴对齐):象限分隔虚线 + 箭头
955
+ slide.addShape('line', { x1: 4.94, y1: 2.15, x2: 4.94, y2: 5.68, line: { color: COLORS.accent, width: 1, dashType: 'dash' } });
956
+ slide.addShape('line', { x1: 0.6, y1: 3.915, x2: 9.28, y2: 3.915, line: { color: COLORS.accent, width: 1, dashType: 'dash' } });
957
+ slide.addShape('triangle', { x: 9.2, y: 3.83, w: 0.14, h: 0.18, fill: { color: COLORS.accent }, rotate: 90 });
958
+ slide.addShape('triangle', { x: 4.86, y: 1.98, w: 0.18, h: 0.14, fill: { color: COLORS.accent } });
959
+ addTheme07GlowLine(slide);
960
+ }
961
+ export function renderTheme07RiskV1(slide, props) {
962
+ if (props.kicker) {
963
+ addTheme07Kicker(slide, props.kicker);
964
+ }
965
+ slide.addText(props.title ?? '', {
966
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
967
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
968
+ });
969
+ if (props.subtitle) {
970
+ slide.addText(props.subtitle, {
971
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
972
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
973
+ });
974
+ }
975
+ slide.addShape('line', {
976
+ x1: 0.65, y1: 2.15, x2: 1.5, y2: 2.15,
977
+ line: { color: COLORS.accent, width: 3 },
978
+ });
979
+ const items = (props.items || []).slice(0, 6);
980
+ if (items.length > 0) {
981
+ const colW = 4.2;
982
+ const rowH = 1.05;
983
+ const startY = 2.4;
984
+ items.forEach((item, idx) => {
985
+ const col = idx % 2;
986
+ const row = Math.floor(idx / 2);
987
+ const x = 0.65 + col * (colW + 0.18);
988
+ const y = startY + row * rowH;
989
+ const level = item.level === 'high' ? 'high' : item.level === 'low' ? 'low' : 'medium';
990
+ const accentColor = level === 'high' ? COLORS.accentCool : level === 'medium' ? 'B45309' : COLORS.accent2;
991
+ addTheme07Card(slide, x, y, colW, rowH - 0.1, 0.08, COLORS.white);
992
+ slide.addShape('rect', {
993
+ x, y, w: 0.05, h: rowH - 0.1,
994
+ fill: { color: accentColor },
995
+ });
996
+ slide.addText(item.risk ?? '', {
997
+ x: x + 0.15, y: y + 0.1, w: colW - 0.3, h: 0.3,
998
+ fontSize: 13, color: COLORS.primary, bold: true, fontFace: FONTS.heading,
999
+ });
1000
+ slide.addText(`影响:${item.impact ?? '中'}`, {
1001
+ x: x + 0.15, y: y + 0.38, w: colW - 0.3, h: 0.22,
1002
+ fontSize: 10, color: accentColor, fontFace: FONTS.mono,
1003
+ });
1004
+ if (item.response) {
1005
+ slide.addText(`应对:${item.response}`, {
1006
+ x: x + 0.15, y: y + 0.58, w: colW - 0.3, h: 0.35,
1007
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1008
+ });
1009
+ }
1010
+ });
1011
+ }
1012
+ if (props.footnote) {
1013
+ slide.addText(props.footnote, {
1014
+ x: 0.65, y: 5.05, w: 8.7, h: 0.25,
1015
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1016
+ });
1017
+ }
1018
+ addTheme07GlowLine(slide);
1019
+ }
1020
+ export function renderTheme07CoverLeanV1(slide, props) {
1021
+ if (props.imageUrl) {
1022
+ addImageMaybe(slide, props.imageUrl, 0, 0, 10, 5.625);
1023
+ }
1024
+ if (props.badge) {
1025
+ addTheme07Kicker(slide, props.badge);
1026
+ }
1027
+ if (props.headline) {
1028
+ slide.addText(props.headline, {
1029
+ x: 0.65, y: 0.9, w: 8.7, h: 0.35,
1030
+ fontSize: 16, color: COLORS.accent, bold: true, fontFace: FONTS.mono, charSpacing: 2,
1031
+ });
1032
+ }
1033
+ const titleY = props.headline ? 1.35 : 0.95;
1034
+ slide.addText(props.title ?? '', {
1035
+ x: 0.65, y: titleY, w: 7.2, h: 0.9,
1036
+ fontSize: 38, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1037
+ });
1038
+ if (props.subtitle) {
1039
+ slide.addText(props.subtitle, {
1040
+ x: 0.65, y: titleY + 1.0, w: 6.5, h: 0.4,
1041
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1042
+ });
1043
+ }
1044
+ const metrics = (props.metrics || []).slice(0, 3);
1045
+ if (metrics.length > 0) {
1046
+ const cardW = 2.75;
1047
+ const startX = 0.65;
1048
+ const gap = (8.7 - cardW * metrics.length) / (metrics.length - 1 || 1);
1049
+ metrics.forEach((m, idx) => {
1050
+ const x = metrics.length === 1 ? startX : startX + idx * (cardW + gap);
1051
+ const y = 4.2;
1052
+ addTheme07Card(slide, x, y, cardW, 0.95, 0.08, COLORS.white);
1053
+ slide.addText(`${m.value ?? ''}${m.unit ?? ''}`, {
1054
+ x: x + 0.12, y: y + 0.1, w: cardW - 0.24, h: 0.4,
1055
+ fontSize: 22, color: COLORS.accent, bold: true, fontFace: FONTS.heading,
1056
+ });
1057
+ slide.addText(m.label ?? '', {
1058
+ x: x + 0.12, y: y + 0.52, w: cardW - 0.24, h: 0.3,
1059
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono,
1060
+ });
1061
+ });
1062
+ }
1063
+ addTheme07Footer(slide, props);
1064
+ addTheme07GlowLine(slide);
1065
+ }
1066
+ export function renderTheme07CoverSupplyChainV1(slide, props) {
1067
+ if (props.imageUrl) {
1068
+ addImageMaybe(slide, props.imageUrl, 0, 0, 10, 5.625);
1069
+ }
1070
+ if (props.badge) {
1071
+ addTheme07Kicker(slide, props.badge);
1072
+ }
1073
+ if (props.headline) {
1074
+ slide.addText(props.headline, {
1075
+ x: 0.65, y: 0.9, w: 4.5, h: 0.35,
1076
+ fontSize: 16, color: COLORS.accent, bold: true, fontFace: FONTS.mono, charSpacing: 2,
1077
+ });
1078
+ }
1079
+ const titleY = props.headline ? 1.35 : 0.95;
1080
+ slide.addText(props.title ?? '', {
1081
+ x: 0.65, y: titleY, w: 4.5, h: 0.9,
1082
+ fontSize: 34, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1083
+ });
1084
+ if (props.subtitle) {
1085
+ slide.addText(props.subtitle, {
1086
+ x: 0.65, y: titleY + 1.0, w: 4.3, h: 0.5,
1087
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1088
+ });
1089
+ }
1090
+ const channels = (props.channels || []).slice(0, 6);
1091
+ if (channels.length > 0) {
1092
+ const colW = 2.1;
1093
+ const rowH = 0.82;
1094
+ const startX = 5.35;
1095
+ const startY = 0.95;
1096
+ channels.forEach((c, idx) => {
1097
+ const col = idx % 2;
1098
+ const row = Math.floor(idx / 2);
1099
+ const x = startX + col * (colW + 0.12);
1100
+ const y = startY + row * (rowH + 0.12);
1101
+ addTheme07Card(slide, x, y, colW, rowH, 0.06, COLORS.white);
1102
+ slide.addText(c.name ?? '', {
1103
+ x: x + 0.1, y: y + 0.08, w: colW - 0.2, h: 0.3,
1104
+ fontSize: 12, color: COLORS.primary, bold: true, fontFace: FONTS.heading,
1105
+ });
1106
+ slide.addText(c.metric ?? '', {
1107
+ x: x + 0.1, y: y + 0.38, w: colW - 0.2, h: 0.3,
1108
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono,
1109
+ });
1110
+ });
1111
+ }
1112
+ addTheme07Footer(slide, props);
1113
+ addTheme07GlowLine(slide);
1114
+ }
1115
+ export function renderTheme07CoverRetailTrendV1(slide, props) {
1116
+ renderTheme07CoverV1(slide, props);
1117
+ }
1118
+ export function renderTheme07CoverSupplyStrategyV1(slide, props) {
1119
+ if (props.imageUrl) {
1120
+ addImageMaybe(slide, props.imageUrl, 0, 0, 10, 5.625);
1121
+ }
1122
+ if (props.badge) {
1123
+ addTheme07Kicker(slide, props.badge);
1124
+ }
1125
+ if (props.hero) {
1126
+ slide.addText(props.hero, {
1127
+ x: 0.65, y: 1.0, w: 8.7, h: 0.4,
1128
+ fontSize: 18, color: COLORS.accent, bold: true, fontFace: FONTS.mono, align: 'center', charSpacing: 2,
1129
+ });
1130
+ }
1131
+ slide.addText(props.title ?? '', {
1132
+ x: 0.65, y: 1.55, w: 8.7, h: 0.7,
1133
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, align: 'center', valign: 'top',
1134
+ });
1135
+ if (props.subtitle) {
1136
+ slide.addText(props.subtitle, {
1137
+ x: 1.5, y: 2.35, w: 7, h: 0.35,
1138
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, align: 'center', valign: 'top',
1139
+ });
1140
+ }
1141
+ const kpis = (props.kpis || []).slice(0, 3);
1142
+ if (kpis.length > 0) {
1143
+ const cardW = 2.6;
1144
+ const gap = (8.7 - cardW * kpis.length) / (kpis.length - 1 || 1);
1145
+ kpis.forEach((k, idx) => {
1146
+ const x = kpis.length === 1 ? 3.7 : 0.65 + idx * (cardW + gap);
1147
+ const y = 3.4;
1148
+ addTheme07Card(slide, x, y, cardW, 1.1, 0.08, COLORS.white);
1149
+ slide.addText(`${k.value ?? ''}${k.unit ?? ''}`, {
1150
+ x: x + 0.12, y: y + 0.15, w: cardW - 0.24, h: 0.5,
1151
+ fontSize: 28, color: COLORS.accent, bold: true, fontFace: FONTS.heading, align: 'center',
1152
+ });
1153
+ slide.addText(k.label ?? '', {
1154
+ x: x + 0.12, y: y + 0.7, w: cardW - 0.24, h: 0.3,
1155
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center',
1156
+ });
1157
+ });
1158
+ }
1159
+ addTheme07Footer(slide, props);
1160
+ addTheme07GlowLine(slide);
1161
+ }
1162
+ export function renderTheme07PeakV1(slide, props) {
1163
+ if (props.kicker) {
1164
+ addTheme07Kicker(slide, props.kicker);
1165
+ }
1166
+ slide.addText(props.title ?? '', {
1167
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
1168
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1169
+ });
1170
+ if (props.subtitle) {
1171
+ slide.addText(props.subtitle, {
1172
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
1173
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1174
+ });
1175
+ }
1176
+ const labels = (props.labels || []).slice(0, 24).map((it) => (typeof it === 'string' ? it : it?.item ?? ''));
1177
+ const data = (props.data || []).slice(0, 24).map((it) => (typeof it === 'number' ? it : Number(it?.item ?? 0) || 0));
1178
+ const showConclusion = props.showConclusion !== false;
1179
+ const hasConclusion = showConclusion && (props.conclusionValue || props.conclusionLabel || props.conclusionDescription);
1180
+ const chartW = hasConclusion ? 5.6 : 8.7;
1181
+ if (labels.length >= 2 && data.length >= 2) {
1182
+ slide.addChart('line', [{ name: '趋势', labels, values: data }], {
1183
+ x: 0.65, y: 2.25, w: chartW, h: 3.0,
1184
+ chartColors: ['2E5C8A'],
1185
+ lineDataSymbol: 'circle',
1186
+ showValue: false,
1187
+ });
1188
+ }
1189
+ if (props.unit) {
1190
+ addTheme07Card(slide, 6.45, 2.25, 2.9, 0.7, 0.08, COLORS.white);
1191
+ slide.addText('单位', { x: 6.6, y: 2.32, w: 2.6, h: 0.2, fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body });
1192
+ slide.addText(props.unit, { x: 6.6, y: 2.52, w: 2.6, h: 0.35, fontSize: 18, color: COLORS.primary, bold: true, fontFace: FONTS.heading });
1193
+ }
1194
+ if (hasConclusion) {
1195
+ const panelY = props.unit ? 3.05 : 2.25;
1196
+ const panelH = props.unit ? 2.2 : 3.0;
1197
+ addTheme07Card(slide, 6.45, panelY, 2.9, panelH, 0.08, COLORS.accent);
1198
+ let cursorY = panelY + 0.18;
1199
+ if (props.conclusionValue) {
1200
+ slide.addText(props.conclusionValue, { x: 6.65, y: cursorY, w: 2.5, h: 0.55, fontSize: 32, color: COLORS.white, bold: true, fontFace: FONTS.heading });
1201
+ cursorY += 0.58;
1202
+ }
1203
+ if (props.conclusionLabel) {
1204
+ slide.addText(props.conclusionLabel, { x: 6.65, y: cursorY, w: 2.5, h: 0.25, fontSize: 10, color: 'FFFFFF', fontFace: FONTS.body });
1205
+ cursorY += 0.32;
1206
+ }
1207
+ if (props.conclusionDescription) {
1208
+ slide.addText(props.conclusionDescription, { x: 6.65, y: cursorY, w: 2.5, h: panelH - (cursorY - panelY) - 0.25, fontSize: 10, color: 'FFFFFF', valign: 'top', fontFace: FONTS.body });
1209
+ }
1210
+ }
1211
+ addTheme07GlowLine(slide);
1212
+ }
1213
+ export function renderTheme07CooldownV1(slide, props) {
1214
+ renderTheme07PeakV1(slide, props);
1215
+ }
1216
+ export function renderTheme07PeakTroughV1(slide, props) {
1217
+ renderTheme07PeakV1(slide, props);
1218
+ }
1219
+ export function renderTheme07DealSizeV1(slide, props) {
1220
+ if (props.kicker) {
1221
+ addTheme07Kicker(slide, props.kicker);
1222
+ }
1223
+ slide.addText(props.title ?? '', {
1224
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
1225
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1226
+ });
1227
+ if (props.subtitle) {
1228
+ slide.addText(props.subtitle, {
1229
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
1230
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1231
+ });
1232
+ }
1233
+ const items = (props.items || []).slice(0, 8).filter((i) => i && i.name);
1234
+ const hasConclusion = !!props.conclusion;
1235
+ const chartW = hasConclusion ? 5.6 : 8.7;
1236
+ if (items.length > 0) {
1237
+ const labels = items.map((i) => i.name);
1238
+ const values = items.map((i) => Number(i.value ?? 0) || 0);
1239
+ slide.addChart('pie', [{ name: '规模', labels, values }], {
1240
+ x: 0.65, y: 2.25, w: chartW, h: 3.0,
1241
+ chartColors: ['2E5C8A', '7B9E7B', 'B8623E', '5B9BD5', '7D8FA3', '9AAFC4'],
1242
+ showValue: true,
1243
+ dataLabelColor: COLORS.primary,
1244
+ dataLabelFontSize: 9,
1245
+ });
1246
+ }
1247
+ if (props.unit) {
1248
+ addTheme07Card(slide, 6.45, 2.25, 2.9, 0.7, 0.08, COLORS.white);
1249
+ slide.addText('单位', { x: 6.6, y: 2.32, w: 2.6, h: 0.2, fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body });
1250
+ slide.addText(props.unit, { x: 6.6, y: 2.52, w: 2.6, h: 0.35, fontSize: 18, color: COLORS.primary, bold: true, fontFace: FONTS.heading });
1251
+ }
1252
+ if (hasConclusion) {
1253
+ const panelY = props.unit ? 3.05 : 2.25;
1254
+ const panelH = props.unit ? 2.2 : 3.0;
1255
+ addTheme07Card(slide, 6.45, panelY, 2.9, panelH, 0.08, COLORS.white);
1256
+ slide.addText(props.conclusion, {
1257
+ x: 6.65, y: panelY + 0.18, w: 2.5, h: panelH - 0.36,
1258
+ fontSize: 11, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1259
+ });
1260
+ }
1261
+ addTheme07GlowLine(slide);
1262
+ }
1263
+ export function renderTheme07AvgTicketV1(slide, props) {
1264
+ if (props.kicker) {
1265
+ addTheme07Kicker(slide, props.kicker);
1266
+ }
1267
+ slide.addText(props.title ?? '', {
1268
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
1269
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1270
+ });
1271
+ if (props.subtitle) {
1272
+ slide.addText(props.subtitle, {
1273
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
1274
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1275
+ });
1276
+ }
1277
+ const intervals = (props.intervals || []).slice(0, 8).map((it) => (typeof it === 'string' ? it : it?.item ?? ''));
1278
+ const values = (props.values || []).slice(0, 8).map((it) => (typeof it === 'number' ? it : Number(it?.item ?? 0) || 0));
1279
+ const hasConclusion = !!props.conclusion;
1280
+ const chartW = hasConclusion ? 5.6 : 8.7;
1281
+ if (intervals.length > 0 && values.length > 0) {
1282
+ slide.addChart('bar', [{ name: '数量', labels: intervals, values }], {
1283
+ x: 0.65, y: 2.25, w: chartW, h: 3.0,
1284
+ chartColors: ['2E5C8A'],
1285
+ showValue: true,
1286
+ dataLabelColor: COLORS.primary,
1287
+ dataLabelFontSize: 9,
1288
+ barGrouping: 'clustered',
1289
+ barDir: 'col',
1290
+ });
1291
+ }
1292
+ if (props.unit) {
1293
+ addTheme07Card(slide, 6.45, 2.25, 2.9, 0.7, 0.08, COLORS.white);
1294
+ slide.addText('单位', { x: 6.6, y: 2.32, w: 2.6, h: 0.2, fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body });
1295
+ slide.addText(props.unit, { x: 6.6, y: 2.52, w: 2.6, h: 0.35, fontSize: 18, color: COLORS.primary, bold: true, fontFace: FONTS.heading });
1296
+ }
1297
+ if (hasConclusion) {
1298
+ const panelY = props.unit ? 3.05 : 2.25;
1299
+ const panelH = props.unit ? 2.2 : 3.0;
1300
+ addTheme07Card(slide, 6.45, panelY, 2.9, panelH, 0.08, COLORS.white);
1301
+ slide.addText(props.conclusion, {
1302
+ x: 6.65, y: panelY + 0.18, w: 2.5, h: panelH - 0.36,
1303
+ fontSize: 11, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1304
+ });
1305
+ }
1306
+ addTheme07GlowLine(slide);
1307
+ }
1308
+ export function renderTheme07OutlookV1(slide, props) {
1309
+ if (props.kicker) {
1310
+ addTheme07Kicker(slide, props.kicker);
1311
+ }
1312
+ slide.addText(props.title ?? '', {
1313
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
1314
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1315
+ });
1316
+ if (props.subtitle) {
1317
+ slide.addText(props.subtitle, {
1318
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
1319
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1320
+ });
1321
+ }
1322
+ slide.addShape('line', {
1323
+ x1: 0.65, y1: 2.15, x2: 1.5, y2: 2.15,
1324
+ line: { color: COLORS.accent, width: 3 },
1325
+ });
1326
+ const points = (props.points || []).slice(0, 4);
1327
+ points.forEach((p, idx) => {
1328
+ const y = 2.45 + idx * 0.55;
1329
+ slide.addShape('ellipse', {
1330
+ x: 0.72, y: y + 0.06, w: 0.18, h: 0.18,
1331
+ fill: { color: COLORS.accent },
1332
+ });
1333
+ slide.addText(String(idx + 1), {
1334
+ x: 0.72, y: y + 0.06, w: 0.18, h: 0.18,
1335
+ fontSize: 10, color: COLORS.white, bold: true, align: 'center', valign: 'middle', fontFace: FONTS.mono,
1336
+ });
1337
+ slide.addText(p.text ?? '', {
1338
+ x: 1.05, y: y, w: 4.0, h: 0.45,
1339
+ fontSize: 12, color: COLORS.primary, fontFace: FONTS.body, valign: 'top',
1340
+ });
1341
+ });
1342
+ const steps = (props.steps || []).slice(0, 4);
1343
+ steps.forEach((step, idx) => {
1344
+ const x = 5.55;
1345
+ const y = 2.25 + idx * 0.82;
1346
+ addTheme07Card(slide, x, y, 3.8, 0.74, 0.08, COLORS.white);
1347
+ slide.addText(step.date ?? '', {
1348
+ x: x + 0.1, y: y + 0.08, w: 0.8, h: 0.22,
1349
+ fontSize: 10, color: COLORS.accent, bold: true, fontFace: FONTS.mono,
1350
+ });
1351
+ slide.addText(step.title ?? '', {
1352
+ x: x + 0.95, y: y + 0.06, w: 2.7, h: 0.25,
1353
+ fontSize: 12, color: COLORS.primary, bold: true, fontFace: FONTS.heading,
1354
+ });
1355
+ slide.addText(step.description ?? '', {
1356
+ x: x + 0.95, y: y + 0.32, w: 2.7, h: 0.35,
1357
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1358
+ });
1359
+ });
1360
+ addTheme07GlowLine(slide);
1361
+ }
1362
+ export function renderTheme07RepricingV1(slide, props) {
1363
+ if (props.kicker) {
1364
+ addTheme07Kicker(slide, props.kicker);
1365
+ }
1366
+ slide.addText(props.title ?? '', {
1367
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
1368
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1369
+ });
1370
+ if (props.subtitle) {
1371
+ slide.addText(props.subtitle, {
1372
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
1373
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1374
+ });
1375
+ }
1376
+ const phases = (props.phases || []).slice(0, 5);
1377
+ if (phases.length > 0) {
1378
+ const cardW = 8.7 / phases.length - 0.15;
1379
+ phases.forEach((phase, idx) => {
1380
+ const x = 0.65 + idx * (cardW + 0.15);
1381
+ const y = 2.25;
1382
+ addTheme07Card(slide, x, y, cardW, 2.6, 0.08, COLORS.white);
1383
+ slide.addShape('ellipse', {
1384
+ x: x + 0.12, y: y + 0.12, w: 0.2, h: 0.2,
1385
+ fill: { color: COLORS.accent },
1386
+ });
1387
+ slide.addText(phase.date ?? '', {
1388
+ x: x + 0.4, y: y + 0.1, w: cardW - 0.55, h: 0.25,
1389
+ fontSize: 11, color: COLORS.accent, bold: true, fontFace: FONTS.mono,
1390
+ });
1391
+ slide.addText(phase.title ?? '', {
1392
+ x: x + 0.12, y: y + 0.45, w: cardW - 0.24, h: 0.35,
1393
+ fontSize: 14, color: COLORS.primary, bold: true, fontFace: FONTS.heading,
1394
+ });
1395
+ slide.addText(phase.description ?? '', {
1396
+ x: x + 0.12, y: y + 0.85, w: cardW - 0.24, h: 1.6,
1397
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1398
+ });
1399
+ if (idx < phases.length - 1) {
1400
+ slide.addText('→', {
1401
+ x: x + cardW + 0.02, y: y + 1.1, w: 0.13, h: 0.3,
1402
+ fontSize: 12, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center',
1403
+ });
1404
+ }
1405
+ });
1406
+ }
1407
+ if (props.footnote) {
1408
+ slide.addText(props.footnote, {
1409
+ x: 0.65, y: 5.05, w: 8.7, h: 0.25,
1410
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1411
+ });
1412
+ }
1413
+ addTheme07GlowLine(slide);
1414
+ }
1415
+ export function renderTheme07DealMapV1(slide, props) {
1416
+ if (props.kicker) {
1417
+ addTheme07Kicker(slide, props.kicker);
1418
+ }
1419
+ slide.addText(props.title ?? '', {
1420
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
1421
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1422
+ });
1423
+ if (props.subtitle) {
1424
+ slide.addText(props.subtitle, {
1425
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
1426
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1427
+ });
1428
+ }
1429
+ const hasConclusion = !!props.conclusion;
1430
+ const chartW = hasConclusion ? 5.6 : 8.7;
1431
+ const nodes = (props.nodes || []).slice(0, 16).filter((n) => n && n.name);
1432
+ if (nodes.length > 0) {
1433
+ const labels = nodes.map((n) => n.name);
1434
+ const values = nodes.map((n) => Number(n.value ?? 50) || 50);
1435
+ slide.addChart('line', [{ name: '节点', labels, values }], {
1436
+ x: 0.65, y: 2.25, w: chartW, h: 3.0,
1437
+ chartColors: ['2E5C8A'],
1438
+ showValue: false,
1439
+ });
1440
+ }
1441
+ if (hasConclusion) {
1442
+ addTheme07Card(slide, 6.45, 2.25, 2.9, 3.0, 0.08, COLORS.white);
1443
+ slide.addText(props.conclusion, {
1444
+ x: 6.65, y: 2.43, w: 2.5, h: 2.64,
1445
+ fontSize: 11, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1446
+ });
1447
+ }
1448
+ addTheme07GlowLine(slide);
1449
+ }
1450
+ export function renderTheme07ColdStartV1(slide, props) {
1451
+ if (props.kicker) {
1452
+ addTheme07Kicker(slide, props.kicker);
1453
+ }
1454
+ if (props.title) {
1455
+ slide.addText(props.title, {
1456
+ x: 0.65, y: 0.95, w: 8.7, h: 0.6,
1457
+ fontSize: 32, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1458
+ });
1459
+ }
1460
+ slide.addText(props.number ?? '', {
1461
+ x: 0.65, y: 1.85, w: 5.5, h: 1.2,
1462
+ fontSize: 72, bold: true, fontFace: FONTS.heading, color: COLORS.accent, valign: 'top',
1463
+ });
1464
+ if (props.unit) {
1465
+ slide.addText(props.unit, {
1466
+ x: 3.9, y: 2.25, w: 2.0, h: 0.5,
1467
+ fontSize: 24, bold: true, fontFace: FONTS.heading, color: COLORS.secondary, valign: 'top',
1468
+ });
1469
+ }
1470
+ if (props.label) {
1471
+ slide.addText(props.label, {
1472
+ x: 0.65, y: 3.15, w: 5.5, h: 0.3,
1473
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.mono, valign: 'top',
1474
+ });
1475
+ }
1476
+ if (props.description) {
1477
+ slide.addText(props.description, {
1478
+ x: 0.65, y: 3.55, w: 5.2, h: 0.8,
1479
+ fontSize: 12, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1480
+ });
1481
+ }
1482
+ const supporting = (props.supporting || []).slice(0, 3);
1483
+ supporting.forEach((item, idx) => {
1484
+ const y = 1.7 + idx * 1.05;
1485
+ addTheme07Card(slide, 6.1, y, 3.25, 0.9, 0.08, COLORS.white);
1486
+ slide.addText(item.value ?? '', {
1487
+ x: 6.25, y: y + 0.1, w: 2.95, h: 0.45,
1488
+ fontSize: 24, color: COLORS.accent, bold: true, fontFace: FONTS.heading,
1489
+ });
1490
+ slide.addText(item.label ?? '', {
1491
+ x: 6.25, y: y + 0.55, w: 2.95, h: 0.3,
1492
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono,
1493
+ });
1494
+ });
1495
+ addTheme07GlowLine(slide);
1496
+ }
1497
+ export function renderTheme07AccelerateV1(slide, props) {
1498
+ if (props.kicker) {
1499
+ addTheme07Kicker(slide, props.kicker);
1500
+ }
1501
+ slide.addText(props.title ?? '', {
1502
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
1503
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, align: 'center', valign: 'top',
1504
+ });
1505
+ if (props.subtitle) {
1506
+ slide.addText(props.subtitle, {
1507
+ x: 1.5, y: 1.7, w: 7, h: 0.35,
1508
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, align: 'center', valign: 'top',
1509
+ });
1510
+ }
1511
+ slide.addText(`${props.value ?? ''}${props.unit ?? ''}`, {
1512
+ x: 0.65, y: 2.35, w: 8.7, h: 1.1,
1513
+ fontSize: 72, bold: true, fontFace: FONTS.heading, color: COLORS.accent, align: 'center', valign: 'top',
1514
+ });
1515
+ if (props.change || props.changeLabel) {
1516
+ const text = [props.change ?? '', props.changeLabel ?? ''].filter(Boolean).join(' · ');
1517
+ addTheme07Card(slide, 3.35, 3.6, 3.3, 0.65, 0.08, COLORS.white);
1518
+ slide.addText(text, {
1519
+ x: 3.5, y: 3.75, w: 3.0, h: 0.35,
1520
+ fontSize: 14, color: COLORS.accent2, bold: true, fontFace: FONTS.mono, align: 'center',
1521
+ });
1522
+ }
1523
+ addTheme07GlowLine(slide);
1524
+ }
1525
+ export function renderTheme07InvestorV1(slide, props) {
1526
+ if (props.kicker) {
1527
+ addTheme07Kicker(slide, props.kicker);
1528
+ }
1529
+ slide.addText(props.title ?? '', {
1530
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
1531
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1532
+ });
1533
+ if (props.subtitle) {
1534
+ slide.addText(props.subtitle, {
1535
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
1536
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1537
+ });
1538
+ }
1539
+ const investors = (props.investors || []).slice(0, 9).filter((i) => i && i.name);
1540
+ if (investors.length > 0) {
1541
+ const colW = 2.8;
1542
+ const rowH = 0.9;
1543
+ const cols = 3;
1544
+ investors.forEach((inv, idx) => {
1545
+ const col = idx % cols;
1546
+ const row = Math.floor(idx / cols);
1547
+ const x = 0.65 + col * (colW + 0.12);
1548
+ const y = 2.25 + row * (rowH + 0.12);
1549
+ const isFocus = idx === 0;
1550
+ addTheme07Card(slide, x, y, colW, rowH, 0.08, isFocus ? COLORS.accent : COLORS.white);
1551
+ const textColor = isFocus ? COLORS.white : COLORS.primary;
1552
+ const subColor = isFocus ? 'D0E0F0' : COLORS.secondary;
1553
+ slide.addText(inv.name, {
1554
+ x: x + 0.12, y: y + 0.12, w: colW - 0.24, h: 0.35,
1555
+ fontSize: 15, color: textColor, bold: true, fontFace: FONTS.heading,
1556
+ });
1557
+ slide.addText([inv.type, inv.stage].filter(Boolean).join(' · '), {
1558
+ x: x + 0.12, y: y + 0.5, w: colW - 0.24, h: 0.28,
1559
+ fontSize: 9, color: subColor, fontFace: FONTS.mono,
1560
+ });
1561
+ });
1562
+ }
1563
+ addTheme07GlowLine(slide);
1564
+ }
1565
+ export function renderTheme07ActiveCapitalV1(slide, props) {
1566
+ if (props.kicker) {
1567
+ addTheme07Kicker(slide, props.kicker);
1568
+ }
1569
+ slide.addText(props.title ?? '', {
1570
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
1571
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1572
+ });
1573
+ if (props.subtitle) {
1574
+ slide.addText(props.subtitle, {
1575
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
1576
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1577
+ });
1578
+ }
1579
+ if (props.company) {
1580
+ slide.addText(props.company, {
1581
+ x: 0.65, y: 2.15, w: 4.0, h: 0.45,
1582
+ fontSize: 22, color: COLORS.accent, bold: true, fontFace: FONTS.heading,
1583
+ });
1584
+ }
1585
+ if (props.tagline) {
1586
+ slide.addText(props.tagline, {
1587
+ x: 0.65, y: 2.6, w: 4.0, h: 0.25,
1588
+ fontSize: 11, color: COLORS.secondary, fontFace: FONTS.body,
1589
+ });
1590
+ }
1591
+ const rounds = (props.rounds || []).slice(0, 6).filter((r) => r && r.round);
1592
+ if (rounds.length > 0) {
1593
+ const cardW = 8.7 / rounds.length - 0.15;
1594
+ rounds.forEach((r, idx) => {
1595
+ const x = 0.65 + idx * (cardW + 0.15);
1596
+ const y = 3.1;
1597
+ const isFocus = idx === rounds.length - 1;
1598
+ addTheme07Card(slide, x, y, cardW, 1.9, 0.08, isFocus ? COLORS.accent : COLORS.white);
1599
+ const textColor = isFocus ? COLORS.white : COLORS.primary;
1600
+ const subColor = isFocus ? 'D0E0F0' : COLORS.secondary;
1601
+ slide.addText(r.date ?? '', {
1602
+ x: x + 0.1, y: y + 0.1, w: cardW - 0.2, h: 0.2,
1603
+ fontSize: 10, color: isFocus ? COLORS.white : COLORS.accent, fontFace: FONTS.mono,
1604
+ });
1605
+ slide.addText(r.round, {
1606
+ x: x + 0.1, y: y + 0.35, w: cardW - 0.2, h: 0.35,
1607
+ fontSize: 14, color: textColor, bold: true, fontFace: FONTS.heading,
1608
+ });
1609
+ slide.addText(r.amount ?? '', {
1610
+ x: x + 0.1, y: y + 0.75, w: cardW - 0.2, h: 0.45,
1611
+ fontSize: 22, color: textColor, bold: true, fontFace: FONTS.heading,
1612
+ });
1613
+ slide.addText(r.investor ?? '', {
1614
+ x: x + 0.1, y: y + 1.25, w: cardW - 0.2, h: 0.45,
1615
+ fontSize: 9, color: subColor, fontFace: FONTS.mono, valign: 'top',
1616
+ });
1617
+ });
1618
+ }
1619
+ addTheme07GlowLine(slide);
1620
+ }
1621
+ export function renderTheme07ConcentrationV1(slide, props) {
1622
+ if (props.kicker) {
1623
+ addTheme07Kicker(slide, props.kicker);
1624
+ }
1625
+ slide.addText(props.title ?? '', {
1626
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
1627
+ fontSize: 36, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1628
+ });
1629
+ if (props.subtitle) {
1630
+ slide.addText(props.subtitle, {
1631
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
1632
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1633
+ });
1634
+ }
1635
+ const rows = (props.rows || []).slice(0, 10).filter((r) => r && r.name);
1636
+ if (rows.length > 0) {
1637
+ const rowH = 0.52;
1638
+ const startY = 2.25;
1639
+ rows.forEach((row, idx) => {
1640
+ const y = startY + idx * rowH;
1641
+ const isFocus = row.focus === true || idx === Number(props.focusIndex ?? 0);
1642
+ if (isFocus) {
1643
+ slide.addShape('roundRect', {
1644
+ x: 0.65, y, w: 8.7, h: rowH - 0.06,
1645
+ fill: { color: COLORS.accent }, rectRadius: 0.06,
1646
+ });
1647
+ }
1648
+ else {
1649
+ addTheme07Card(slide, 0.65, y, 8.7, rowH - 0.06, 0.06, COLORS.white);
1650
+ }
1651
+ const textColor = isFocus ? COLORS.white : COLORS.primary;
1652
+ const valueColor = isFocus ? COLORS.white : COLORS.accent;
1653
+ slide.addText(String(idx + 1).padStart(2, '0'), {
1654
+ x: 0.85, y: y + 0.08, w: 0.5, h: 0.3,
1655
+ fontSize: 15, color: valueColor, bold: true, fontFace: FONTS.heading,
1656
+ });
1657
+ slide.addText(row.name, {
1658
+ x: 1.45, y: y + 0.1, w: 4.5, h: 0.3,
1659
+ fontSize: 14, color: textColor, bold: true, fontFace: FONTS.body,
1660
+ });
1661
+ slide.addText(row.value ?? '', {
1662
+ x: 6.8, y: y + 0.08, w: 1.2, h: 0.32,
1663
+ fontSize: 16, color: valueColor, bold: true, fontFace: FONTS.mono, align: 'right',
1664
+ });
1665
+ if (row.change) {
1666
+ slide.addText(row.change, {
1667
+ x: 8.1, y: y + 0.1, w: 0.9, h: 0.28,
1668
+ fontSize: 11, color: row.change.startsWith('-') ? COLORS.accentCool : COLORS.accent2, fontFace: FONTS.mono, align: 'right',
1669
+ });
1670
+ }
1671
+ });
1672
+ }
1673
+ addTheme07GlowLine(slide);
1674
+ }
1675
+ export function renderTheme07SyndicateV1(slide, props) {
1676
+ if (props.kicker) {
1677
+ addTheme07Kicker(slide, props.kicker);
1678
+ }
1679
+ slide.addText(props.statement ?? '', {
1680
+ x: 0.65, y: 1.15, w: 8.7, h: 1.0,
1681
+ fontSize: 28, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1682
+ });
1683
+ if (props.subtitle) {
1684
+ slide.addText(props.subtitle, {
1685
+ x: 0.65, y: 2.25, w: 8.7, h: 0.3,
1686
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1687
+ });
1688
+ }
1689
+ const points = (props.points || []).slice(0, 4);
1690
+ points.forEach((p, idx) => {
1691
+ const y = 2.75 + idx * 0.55;
1692
+ slide.addShape('ellipse', {
1693
+ x: 0.72, y: y + 0.06, w: 0.18, h: 0.18,
1694
+ fill: { color: COLORS.accent },
1695
+ });
1696
+ slide.addText(String(idx + 1), {
1697
+ x: 0.72, y: y + 0.06, w: 0.18, h: 0.18,
1698
+ fontSize: 10, color: COLORS.white, bold: true, align: 'center', valign: 'middle', fontFace: FONTS.mono,
1699
+ });
1700
+ slide.addText(p.text ?? '', {
1701
+ x: 1.05, y: y, w: 8.0, h: 0.45,
1702
+ fontSize: 12, color: COLORS.primary, fontFace: FONTS.body, valign: 'top',
1703
+ });
1704
+ });
1705
+ if (props.source) {
1706
+ slide.addText(props.source, {
1707
+ x: 0.65, y: 5.05, w: 8.7, h: 0.25,
1708
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono, valign: 'top',
1709
+ });
1710
+ }
1711
+ addTheme07GlowLine(slide);
1712
+ }
1713
+ export function renderTheme07SectorV1(slide, props) {
1714
+ if (props.kicker) {
1715
+ addTheme07Kicker(slide, props.kicker);
1716
+ }
1717
+ slide.addText(props.title ?? '', {
1718
+ x: 0.65, y: 0.9, w: 8.7, h: 0.75,
1719
+ fontSize: 34, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1720
+ });
1721
+ if (props.subtitle) {
1722
+ slide.addText(props.subtitle, {
1723
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
1724
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1725
+ });
1726
+ }
1727
+ slide.addShape('line', {
1728
+ x1: 0.65, y1: 2.1, x2: 1.5, y2: 2.1,
1729
+ line: { color: COLORS.accent, width: 3 },
1730
+ });
1731
+ const leftW = 4.7;
1732
+ const rightX = 5.6;
1733
+ const rightW = 3.75;
1734
+ // 左侧描述
1735
+ if (props.description) {
1736
+ slide.addText(props.description, {
1737
+ x: 0.65, y: 2.35, w: leftW, h: 0.7,
1738
+ fontSize: 12, color: COLORS.primary, fontFace: FONTS.body, valign: 'top',
1739
+ });
1740
+ }
1741
+ // 左侧要点
1742
+ const bullets = (props.bullets || [])
1743
+ .map((b) => (typeof b === 'string' ? { title: b, desc: '' } : b))
1744
+ .filter((b) => b && (b.title || b.desc));
1745
+ if (bullets.length > 0) {
1746
+ const startY = props.description ? 3.15 : 2.35;
1747
+ const itemH = 0.55;
1748
+ bullets.slice(0, 6).forEach((item, idx) => {
1749
+ const y = startY + idx * itemH;
1750
+ slide.addText(String(idx + 1).padStart(2, '0'), {
1751
+ x: 0.65, y, w: 0.45, h: 0.35,
1752
+ fontSize: 16, color: COLORS.accent, bold: true, fontFace: FONTS.heading,
1753
+ });
1754
+ if (item.title) {
1755
+ slide.addText(item.title, {
1756
+ x: 1.15, y, w: leftW - 0.5, h: 0.25,
1757
+ fontSize: 12, color: COLORS.primary, bold: true, fontFace: FONTS.body, valign: 'top',
1758
+ });
1759
+ }
1760
+ if (item.desc) {
1761
+ slide.addText(item.desc, {
1762
+ x: 1.15, y: y + 0.22, w: leftW - 0.5, h: 0.28,
1763
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1764
+ });
1765
+ }
1766
+ });
1767
+ }
1768
+ // 右侧图表占位
1769
+ const hasChart = props.chartType && props.chartOption && Object.keys(props.chartOption).length > 0;
1770
+ let rightY = 0.9;
1771
+ if (hasChart) {
1772
+ addTheme07Card(slide, rightX, rightY, rightW, 1.9, 0.08, COLORS.white);
1773
+ slide.addText('CHART', {
1774
+ x: rightX, y: rightY + 0.75, w: rightW, h: 0.3,
1775
+ fontSize: 11, color: COLORS.secondary, bold: true, fontFace: FONTS.mono, align: 'center',
1776
+ charSpacing: 2,
1777
+ });
1778
+ rightY += 2.05;
1779
+ }
1780
+ // 右侧指标
1781
+ const metrics = (props.metrics || []).filter((m) => m && (m.value || m.label));
1782
+ if (metrics.length > 0) {
1783
+ const cardH = 0.85;
1784
+ const cols = Math.min(metrics.length, 2);
1785
+ metrics.slice(0, 4).forEach((m, idx) => {
1786
+ const col = idx % cols;
1787
+ const row = Math.floor(idx / cols);
1788
+ const cardW = (rightW - (cols - 1) * 0.1) / cols;
1789
+ const x = rightX + col * (cardW + 0.1);
1790
+ const y = rightY + row * (cardH + 0.1);
1791
+ addTheme07Card(slide, x, y, cardW, cardH, 0.06, m.accent ? COLORS.accent : COLORS.white);
1792
+ const valueColor = m.accent ? COLORS.white : COLORS.accent;
1793
+ const labelColor = m.accent ? COLORS.white : COLORS.secondary;
1794
+ slide.addText(m.value ?? '', {
1795
+ x: x + 0.08, y: y + 0.1, w: cardW - 0.16, h: 0.35,
1796
+ fontSize: 20, color: valueColor, bold: true, fontFace: FONTS.heading,
1797
+ });
1798
+ if (m.label) {
1799
+ slide.addText(m.label, {
1800
+ x: x + 0.08, y: y + 0.48, w: cardW - 0.16, h: 0.25,
1801
+ fontSize: 9, color: labelColor, fontFace: FONTS.mono,
1802
+ });
1803
+ }
1804
+ });
1805
+ rightY += Math.ceil(metrics.length / cols) * 0.95 + 0.1;
1806
+ }
1807
+ // 右侧洞察
1808
+ if (props.showInsight !== false && props.insight && (props.insight.value || props.insight.label || props.insight.description)) {
1809
+ const ins = props.insight;
1810
+ const insightH = ins.description ? 1.2 : 0.75;
1811
+ addTheme07Card(slide, rightX, rightY, rightW, insightH, 0.08, COLORS.white);
1812
+ slide.addShape('rect', {
1813
+ x: rightX, y: rightY, w: 0.06, h: insightH,
1814
+ fill: { color: COLORS.accent },
1815
+ });
1816
+ let dy = 0.12;
1817
+ if (ins.value) {
1818
+ slide.addText(ins.value, {
1819
+ x: rightX + 0.15, y: rightY + dy, w: rightW - 0.3, h: 0.35,
1820
+ fontSize: 24, color: COLORS.accent, bold: true, fontFace: FONTS.heading,
1821
+ });
1822
+ dy += 0.35;
1823
+ }
1824
+ if (ins.label) {
1825
+ slide.addText(ins.label, {
1826
+ x: rightX + 0.15, y: rightY + dy, w: rightW - 0.3, h: 0.2,
1827
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono,
1828
+ });
1829
+ dy += 0.22;
1830
+ }
1831
+ if (ins.description) {
1832
+ slide.addText(ins.description, {
1833
+ x: rightX + 0.15, y: rightY + dy, w: rightW - 0.3, h: 0.55,
1834
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1835
+ });
1836
+ }
1837
+ }
1838
+ if (props.footnote) {
1839
+ slide.addText(props.footnote, {
1840
+ x: 0.65, y: 4.95, w: 8.7, h: 0.3,
1841
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1842
+ });
1843
+ }
1844
+ addTheme07GlowLine(slide);
1845
+ }
1846
+ export function renderTheme07TableV1(slide, props) {
1847
+ if (props.kicker) {
1848
+ addTheme07Kicker(slide, props.kicker);
1849
+ }
1850
+ slide.addText(props.title ?? '', {
1851
+ x: 0.65, y: 0.9, w: 8.7, h: 0.75,
1852
+ fontSize: 34, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1853
+ });
1854
+ if (props.subtitle) {
1855
+ slide.addText(props.subtitle, {
1856
+ x: 0.65, y: 1.65, w: 8.7, h: 0.35,
1857
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1858
+ });
1859
+ }
1860
+ if (props.intro) {
1861
+ slide.addText(props.intro, {
1862
+ x: 0.65, y: props.subtitle ? 2.05 : 1.65, w: 8.7, h: 0.35,
1863
+ fontSize: 11, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1864
+ });
1865
+ }
1866
+ const headers = (props.headers || [])
1867
+ .map((h) => (typeof h === 'string' ? h : h?.item))
1868
+ .filter(Boolean);
1869
+ const rows = (props.rows || [])
1870
+ .map((r) => {
1871
+ const cells = (r.cells || [])
1872
+ .slice(0, headers.length || 6)
1873
+ .map((c) => (typeof c === 'string' ? { value: c, accent: false } : { value: c?.value ?? '', accent: !!c?.accent }));
1874
+ return { cells, accent: !!r.accent };
1875
+ })
1876
+ .filter((r) => r.cells.some((c) => c.value));
1877
+ if (headers.length > 0 && rows.length > 0) {
1878
+ const tableW = 8.7;
1879
+ const startY = props.intro ? 2.45 : props.subtitle ? 2.1 : 1.65;
1880
+ const colW = tableW / headers.length;
1881
+ const rowH = Math.min(0.55, 3.0 / Math.max(rows.length, 5));
1882
+ const maxRows = Math.floor(3.4 / rowH);
1883
+ // 表头
1884
+ addTheme07Card(slide, 0.65, startY, tableW, rowH, 0.04, COLORS.accent);
1885
+ headers.forEach((h, idx) => {
1886
+ slide.addText(h, {
1887
+ x: 0.65 + idx * colW, y: startY + 0.08, w: colW, h: rowH - 0.16,
1888
+ fontSize: 11, color: COLORS.white, bold: true, fontFace: FONTS.mono, align: 'center', valign: 'middle',
1889
+ });
1890
+ });
1891
+ // 表格行
1892
+ rows.slice(0, maxRows).forEach((row, rIdx) => {
1893
+ const y = startY + (rIdx + 1) * rowH;
1894
+ const fill = row.accent ? COLORS.accent : COLORS.white;
1895
+ addTheme07Card(slide, 0.65, y, tableW, rowH - 0.02, 0.02, fill);
1896
+ row.cells.forEach((cell, cIdx) => {
1897
+ const textColor = row.accent ? COLORS.white : cell.accent ? COLORS.accent : COLORS.primary;
1898
+ slide.addText(cell.value, {
1899
+ x: 0.65 + cIdx * colW + 0.06, y: y + 0.06, w: colW - 0.12, h: rowH - 0.14,
1900
+ fontSize: 10, color: textColor, fontFace: FONTS.body, align: cIdx === 0 ? 'left' : 'center', valign: 'middle',
1901
+ });
1902
+ });
1903
+ });
1904
+ }
1905
+ if (props.conclusion) {
1906
+ slide.addText(props.conclusion, {
1907
+ x: 0.65, y: 4.7, w: 8.7, h: 0.5,
1908
+ fontSize: 12, color: COLORS.primary, bold: true, fontFace: FONTS.body, valign: 'top',
1909
+ });
1910
+ }
1911
+ if (props.footnote) {
1912
+ slide.addText(props.footnote, {
1913
+ x: 0.65, y: 5.0, w: 8.7, h: 0.25,
1914
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1915
+ });
1916
+ }
1917
+ addTheme07GlowLine(slide);
1918
+ }
1919
+ export function renderTheme07CompanyV1(slide, props) {
1920
+ if (props.kicker) {
1921
+ addTheme07Kicker(slide, props.kicker);
1922
+ }
1923
+ slide.addText(props.name ?? '', {
1924
+ x: 0.65, y: 0.9, w: 4.7, h: 0.75,
1925
+ fontSize: 38, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
1926
+ });
1927
+ if (props.tagline) {
1928
+ slide.addText(props.tagline, {
1929
+ x: 0.65, y: 1.6, w: 4.7, h: 0.35,
1930
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
1931
+ });
1932
+ }
1933
+ if (props.description) {
1934
+ slide.addText(props.description, {
1935
+ x: 0.65, y: props.tagline ? 2.05 : 1.6, w: 4.7, h: 1.1,
1936
+ fontSize: 12, color: COLORS.primary, fontFace: FONTS.body, valign: 'top',
1937
+ });
1938
+ }
1939
+ const tags = (props.tags || [])
1940
+ .map((t) => (typeof t === 'string' ? t : t?.item))
1941
+ .filter(Boolean);
1942
+ if (tags.length > 0) {
1943
+ let tagX = 0.65;
1944
+ const tagY = 3.35;
1945
+ tags.slice(0, 6).forEach((tag) => {
1946
+ const w = Math.min(1.8, 0.25 + tag.length * 0.12);
1947
+ addTheme07Card(slide, tagX, tagY, w, 0.32, 0.04, COLORS.white);
1948
+ slide.addText(tag, {
1949
+ x: tagX + 0.05, y: tagY + 0.05, w: w - 0.1, h: 0.22,
1950
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center',
1951
+ });
1952
+ tagX += w + 0.1;
1953
+ });
1954
+ }
1955
+ const metrics = (props.metrics || []).filter((m) => m && (m.value || m.label));
1956
+ if (metrics.length > 0) {
1957
+ const metricY = tags.length > 0 ? 3.85 : 3.35;
1958
+ const metricW = 4.7 / Math.min(metrics.length, 4);
1959
+ metrics.slice(0, 4).forEach((m, idx) => {
1960
+ const x = 0.65 + idx * metricW;
1961
+ slide.addText(m.value ?? '', {
1962
+ x, y: metricY, w: metricW - 0.12, h: 0.35,
1963
+ fontSize: 20, color: COLORS.accent, bold: true, fontFace: FONTS.heading,
1964
+ });
1965
+ if (m.label) {
1966
+ slide.addText(m.label, {
1967
+ x, y: metricY + 0.32, w: metricW - 0.12, h: 0.2,
1968
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono,
1969
+ });
1970
+ }
1971
+ });
1972
+ }
1973
+ // 右侧图片区域(匹配参考 PPT DROP MEDIA 设计)
1974
+ const rightX = 5.6;
1975
+ const rightW = 3.75;
1976
+ const imgH = 2.6;
1977
+ const imgY = 0.85;
1978
+ addTheme07Card(slide, rightX, imgY, rightW, imgH, 0.08, COLORS.white);
1979
+ if (props.imageUrl) {
1980
+ addImageMaybe(slide, props.imageUrl, rightX + 0.08, imgY + 0.08, rightW - 0.16, imgH - 0.16);
1981
+ }
1982
+ else {
1983
+ // DROP MEDIA 占位:标签 pill + 居中文字 + 底部名称
1984
+ if (props.imageTag) {
1985
+ slide.addShape('roundRect', {
1986
+ x: rightX + 0.15, y: imgY + 0.15, w: 1.1, h: 0.28,
1987
+ fill: { color: '#7B9E7B' }, rectRadius: 0.14,
1988
+ });
1989
+ slide.addText(props.imageTag, {
1990
+ x: rightX + 0.15, y: imgY + 0.17, w: 1.1, h: 0.24,
1991
+ fontSize: 9, color: COLORS.white, bold: true, fontFace: FONTS.mono, align: 'center',
1992
+ });
1993
+ }
1994
+ slide.addText('DROP MEDIA', {
1995
+ x: rightX, y: imgY + imgH * 0.38, w: rightW, h: 0.3,
1996
+ fontSize: 11, color: '#90B090', fontFace: FONTS.mono, align: 'center', charSpacing: 2,
1997
+ });
1998
+ slide.addText(props.name ?? '', {
1999
+ x: rightX + 0.15, y: imgY + imgH - 0.45, w: rightW - 0.3, h: 0.32,
2000
+ fontSize: 16, bold: true, fontFace: FONTS.heading, color: COLORS.primary,
2001
+ });
2002
+ }
2003
+ if (props.quote) {
2004
+ addTheme07Card(slide, rightX, 3.35, rightW, 1.25, 0.08, COLORS.white);
2005
+ slide.addText(`“${props.quote}”`, {
2006
+ x: rightX + 0.12, y: 3.45, w: rightW - 0.24, h: 0.75,
2007
+ fontSize: 12, color: COLORS.primary, fontFace: FONTS.body, valign: 'top',
2008
+ });
2009
+ if (props.author) {
2010
+ slide.addText(`— ${props.author}`, {
2011
+ x: rightX + 0.12, y: 4.2, w: rightW - 0.24, h: 0.25,
2012
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono, valign: 'top',
2013
+ });
2014
+ }
2015
+ }
2016
+ if (props.footnote) {
2017
+ slide.addText(props.footnote, {
2018
+ x: 0.65, y: 4.95, w: 8.7, h: 0.3,
2019
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2020
+ });
2021
+ }
2022
+ addTheme07GlowLine(slide);
2023
+ }
2024
+ export function renderTheme07GeoV1(slide, props) {
2025
+ if (props.kicker) {
2026
+ addTheme07Kicker(slide, props.kicker);
2027
+ }
2028
+ slide.addText(props.title ?? '', {
2029
+ x: 0.65, y: 0.9, w: 8.7, h: 0.75,
2030
+ fontSize: 34, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
2031
+ });
2032
+ if (props.subtitle) {
2033
+ slide.addText(props.subtitle, {
2034
+ x: 0.65, y: 1.65, w: 8.7, h: 0.35,
2035
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2036
+ });
2037
+ }
2038
+ const regions = (props.regions || [])
2039
+ .filter((r) => r && r.name)
2040
+ .slice(0, 8);
2041
+ const leftW = 4.7;
2042
+ const rightX = 5.6;
2043
+ const rightW = 3.75;
2044
+ if (regions.length > 0) {
2045
+ const startY = 2.15;
2046
+ const rowH = 0.55;
2047
+ regions.forEach((r, idx) => {
2048
+ const y = startY + idx * rowH;
2049
+ slide.addText(r.name, {
2050
+ x: 0.65, y, w: 1.5, h: 0.28,
2051
+ fontSize: 12, color: COLORS.primary, bold: true, fontFace: FONTS.body, valign: 'top',
2052
+ });
2053
+ const meta = [r.value, r.note].filter(Boolean).join(' · ');
2054
+ if (meta) {
2055
+ slide.addText(meta, {
2056
+ x: 2.2, y, w: 2.15, h: 0.28,
2057
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, align: 'right', valign: 'top',
2058
+ });
2059
+ }
2060
+ // 进度条背景
2061
+ slide.addShape('roundRect', {
2062
+ x: 0.65, y: y + 0.3, w: leftW, h: 0.08,
2063
+ fill: { color: COLORS.light },
2064
+ rectRadius: 0.04,
2065
+ });
2066
+ const pct = Math.max(0, Math.min(100, r.percent ?? 0));
2067
+ if (pct > 0) {
2068
+ slide.addShape('roundRect', {
2069
+ x: 0.65, y: y + 0.3, w: leftW * (pct / 100), h: 0.08,
2070
+ fill: { color: COLORS.accent },
2071
+ rectRadius: 0.04,
2072
+ });
2073
+ }
2074
+ });
2075
+ }
2076
+ // 右侧装饰圆圈(匹配参考 PPT page053)
2077
+ if (props.imageUrl) {
2078
+ addImageMaybe(slide, props.imageUrl, rightX + 0.1, 1.5, rightW - 0.2, 3.0);
2079
+ }
2080
+ else {
2081
+ // 装饰性半透明圆圈(pptxgenjs 仅支持 6 位 hex)
2082
+ slide.addShape('ellipse', {
2083
+ x: rightX + 0.3, y: 1.3, w: 2.4, h: 2.4,
2084
+ fill: { color: 'C8DCC8' }, line: { color: 'B8CCB8', width: 0.5 },
2085
+ });
2086
+ slide.addShape('ellipse', {
2087
+ x: rightX + 0.8, y: 2.2, w: 1.8, h: 1.8,
2088
+ fill: { color: 'D8E8D8' }, line: { color: 'B8CCB8', width: 0.5 },
2089
+ });
2090
+ slide.addShape('ellipse', {
2091
+ x: rightX + 1.6, y: 2.7, w: 1.3, h: 1.3,
2092
+ fill: { color: 'E8F2E8' }, line: { color: 'C8DCC8', width: 0.5 },
2093
+ });
2094
+ }
2095
+ if (props.footnote) {
2096
+ slide.addText(props.footnote, {
2097
+ x: 0.65, y: 4.95, w: 8.7, h: 0.3,
2098
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2099
+ });
2100
+ }
2101
+ addTheme07GlowLine(slide);
2102
+ }
2103
+ export function renderTheme07ClosingV1(slide, props) {
2104
+ // v2 坐标系统:从 theme07-layout-coordinates.json 读取,缺失时回退到默认值
2105
+ const coords = getLayoutCoordinates('theme07_closing_v1');
2106
+ const c = coords; // 简写
2107
+ const _x = (val, fallback) => (val ?? fallback);
2108
+ const _cx = (key, fallback) => _x(c[key]?.x, fallback);
2109
+ const _cy = (key, fallback) => _x(c[key]?.y, fallback);
2110
+ if (props.kicker) {
2111
+ addTheme07Kicker(slide, props.kicker);
2112
+ }
2113
+ const images = (props.images || []).slice(0, 3);
2114
+ const hasImages = images.length > 0;
2115
+ // 有图片时内容区变窄,右侧留出图片区
2116
+ const contentW = hasImages ? 5.4 : 8.7;
2117
+ const imgAreaX = _cx('image', 6.2);
2118
+ const imgAreaW = _x(c.image?.w, 3.2);
2119
+ slide.addText(props.statement ?? '', {
2120
+ x: _cx('heading', 0.65), y: _cy('heading', 1.4), w: contentW, h: hasImages ? 1.2 : 1.6,
2121
+ fontSize: hasImages ? 32 : 40, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
2122
+ });
2123
+ if (props.subtitle) {
2124
+ slide.addText(props.subtitle, {
2125
+ x: _cx('title', 0.65), y: _cy('title', hasImages ? 2.55 : 3.1), w: contentW, h: 0.45,
2126
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2127
+ });
2128
+ }
2129
+ const points = (props.points || [])
2130
+ .map((p) => (typeof p === 'string' ? { text: p } : p))
2131
+ .filter((p) => p && p.text)
2132
+ .slice(0, 4);
2133
+ if (points.length > 0) {
2134
+ const startY = props.subtitle ? (hasImages ? 3.05 : 3.7) : (hasImages ? 2.55 : 3.1);
2135
+ const pointH = 0.42;
2136
+ points.forEach((p, idx) => {
2137
+ const y = startY + idx * pointH;
2138
+ slide.addShape('ellipse', {
2139
+ x: _cx('list', 0.65), y: y + 0.08, w: 0.1, h: 0.1,
2140
+ fill: { color: COLORS.accent },
2141
+ });
2142
+ slide.addText(p.text, {
2143
+ x: 0.9, y, w: contentW - 0.35, h: 0.38,
2144
+ fontSize: 11, color: COLORS.primary, fontFace: FONTS.body, valign: 'top',
2145
+ });
2146
+ });
2147
+ }
2148
+ // 右侧图片区域(匹配参考 PPT page071)
2149
+ if (hasImages) {
2150
+ const imgH = 1.7;
2151
+ const imgGap = 0.15;
2152
+ images.forEach((img, idx) => {
2153
+ const iy = 1.0 + idx * (imgH + imgGap);
2154
+ addTheme07Card(slide, imgAreaX, iy, imgAreaW, imgH, 0.06, '#F0F4EF');
2155
+ if (img.url) {
2156
+ addImageMaybe(slide, img.url, imgAreaX + 0.06, iy + 0.06, imgAreaW - 0.12, imgH - 0.12);
2157
+ }
2158
+ else {
2159
+ // DROP MEDIA 占位
2160
+ if (img.tag) {
2161
+ slide.addShape('roundRect', {
2162
+ x: imgAreaX + 0.12, y: iy + 0.12, w: 0.9, h: 0.24,
2163
+ fill: { color: '#7B9E7B' }, rectRadius: 0.12,
2164
+ });
2165
+ slide.addText(img.tag, {
2166
+ x: imgAreaX + 0.12, y: iy + 0.14, w: 0.9, h: 0.2,
2167
+ fontSize: 8, color: COLORS.white, bold: true, fontFace: FONTS.mono, align: 'center',
2168
+ });
2169
+ }
2170
+ slide.addText('DROP MEDIA', {
2171
+ x: imgAreaX, y: iy + imgH * 0.42, w: imgAreaW, h: 0.22,
2172
+ fontSize: 10, color: '#A0C0A0', fontFace: FONTS.mono, align: 'center', charSpacing: 1.5,
2173
+ });
2174
+ if (img.label) {
2175
+ slide.addText(img.label, {
2176
+ x: imgAreaX + 0.12, y: iy + imgH - 0.35, w: imgAreaW - 0.24, h: 0.25,
2177
+ fontSize: 11, bold: true, fontFace: FONTS.heading, color: COLORS.primary,
2178
+ });
2179
+ }
2180
+ }
2181
+ });
2182
+ }
2183
+ if (props.source) {
2184
+ slide.addText(`— ${props.source}`, {
2185
+ x: _cx('footer', 0.65), y: _cy('footer', 4.85), w: 8.7, h: 0.25,
2186
+ fontSize: 11, color: COLORS.secondary, fontFace: FONTS.mono, valign: 'top',
2187
+ });
2188
+ }
2189
+ if (props.footnoteLeft || props.footnoteRight) {
2190
+ addTheme07Footer(slide, props);
2191
+ }
2192
+ addTheme07GlowLine(slide);
2193
+ }
2194
+ export function renderTheme07ClosingQuoteV1(slide, props) {
2195
+ if (props.kicker) {
2196
+ addTheme07Kicker(slide, props.kicker);
2197
+ }
2198
+ // 巨号引号装饰
2199
+ slide.addText('“', {
2200
+ x: 4.35, y: 0.45, w: 1.3, h: 1.1,
2201
+ fontSize: 80, bold: true, color: COLORS.accent, fontFace: FONTS.heading, align: 'center',
2202
+ });
2203
+ // 引语正文:将 [[关键词]] 渲染为强调色高亮 run
2204
+ const stmt = String(props.statement ?? '');
2205
+ const parts = stmt.split(/(\[\[.+?\]\])/g).filter(Boolean);
2206
+ const runs = parts.map((p) => {
2207
+ const m = p.match(/^\[\[(.+)\]\]$/);
2208
+ if (m)
2209
+ return { text: m[1], options: { color: COLORS.accent, bold: true } };
2210
+ return { text: p, options: { color: COLORS.primary } };
2211
+ });
2212
+ slide.addText(runs, {
2213
+ x: 0.8, y: 1.55, w: 8.4, h: 2.2,
2214
+ fontSize: 30, bold: true, fontFace: FONTS.heading, align: 'center', valign: 'top',
2215
+ });
2216
+ if (props.subtitle) {
2217
+ slide.addText(props.subtitle, {
2218
+ x: 1.5, y: 3.95, w: 7.0, h: 0.5,
2219
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, align: 'center',
2220
+ });
2221
+ }
2222
+ if (props.source) {
2223
+ slide.addText(`— ${props.source}`, {
2224
+ x: 1.5, y: 4.55, w: 7.0, h: 0.3,
2225
+ fontSize: 12, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center',
2226
+ });
2227
+ }
2228
+ if (props.footnoteLeft || props.footnoteRight) {
2229
+ addTheme07Footer(slide, props);
2230
+ }
2231
+ addTheme07GlowLine(slide);
2232
+ }
2233
+ export function renderTheme07StatHeroV1(slide, props) {
2234
+ if (props.kicker) {
2235
+ addTheme07Kicker(slide, props.kicker);
2236
+ }
2237
+ slide.addText(props.title ?? '', {
2238
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
2239
+ fontSize: 32, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
2240
+ });
2241
+ if (props.subtitle) {
2242
+ slide.addText(props.subtitle, {
2243
+ x: 0.65, y: 1.65, w: 8.7, h: 0.4,
2244
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2245
+ });
2246
+ }
2247
+ const hasImage = !!props.imageUrl;
2248
+ const numberW = hasImage ? 6.2 : 8.7;
2249
+ slide.addText(props.number ?? '', {
2250
+ x: 0.65, y: 2.35, w: numberW, h: 1.9,
2251
+ fontSize: 120, bold: true, fontFace: FONTS.heading, color: COLORS.accent, valign: 'top',
2252
+ });
2253
+ if (props.unit) {
2254
+ slide.addText(props.unit, {
2255
+ x: 0.65, y: 4.25, w: numberW, h: 0.5,
2256
+ fontSize: 24, bold: true, fontFace: FONTS.heading, color: COLORS.secondary, valign: 'top',
2257
+ });
2258
+ }
2259
+ if (props.caption) {
2260
+ slide.addText(props.caption, {
2261
+ x: 0.65, y: 4.8, w: numberW, h: 0.35,
2262
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2263
+ });
2264
+ }
2265
+ // 分隔标尺(纯装饰,仿 .lp-theme07-stat-hero-rule)
2266
+ if (props.showRule !== false) {
2267
+ slide.addShape('line', {
2268
+ x1: 0.65, y1: 4.15, x2: hasImage ? 6.85 : 5.0, y2: 4.15,
2269
+ line: { color: COLORS.accent, width: 1, transparency: 70 },
2270
+ });
2271
+ }
2272
+ if (hasImage) {
2273
+ addImageMaybe(slide, props.imageUrl, 7.1, 2.35, 2.25, 2.35);
2274
+ }
2275
+ addTheme07GlowLine(slide);
2276
+ }
2277
+ export function renderTheme07StatRowV1(slide, props) {
2278
+ if (props.kicker) {
2279
+ addTheme07Kicker(slide, props.kicker);
2280
+ }
2281
+ slide.addText(props.title ?? '', {
2282
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
2283
+ fontSize: 32, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
2284
+ });
2285
+ if (props.subtitle) {
2286
+ slide.addText(props.subtitle, {
2287
+ x: 0.65, y: 1.6, w: 8.7, h: 0.4,
2288
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2289
+ });
2290
+ }
2291
+ const stats = (props.stats || [])
2292
+ .filter((s) => s && s.value)
2293
+ .slice(0, 4);
2294
+ if (stats.length > 0) {
2295
+ const cols = stats.length;
2296
+ const gap = 0.2;
2297
+ const cardW = (8.7 - (cols - 1) * gap) / cols;
2298
+ const cardY = 2.3;
2299
+ const cardH = 2.05;
2300
+ const valueSize = cols >= 4 ? 38 : cols === 3 ? 44 : 52;
2301
+ stats.forEach((stat, idx) => {
2302
+ const x = 0.65 + idx * (cardW + gap);
2303
+ const focus = idx === (props.focusIndex ?? 0);
2304
+ addTheme07Card(slide, x, cardY, cardW, cardH, 0.08, focus ? COLORS.accent : COLORS.white);
2305
+ const valueColor = focus ? COLORS.white : COLORS.accent;
2306
+ const subColor = focus ? 'D0E0F0' : COLORS.secondary;
2307
+ const labelColor = focus ? COLORS.white : COLORS.primary;
2308
+ slide.addText(`${stat.value ?? ''}`, {
2309
+ x: x + 0.15, y: cardY + 0.28, w: cardW - 0.3, h: 0.8,
2310
+ fontSize: valueSize, bold: true, fontFace: FONTS.heading, color: valueColor, valign: 'top',
2311
+ });
2312
+ if (stat.unit) {
2313
+ slide.addText(stat.unit, {
2314
+ x: x + 0.15, y: cardY + 1.05, w: cardW - 0.3, h: 0.3,
2315
+ fontSize: 13, color: subColor, fontFace: FONTS.mono, valign: 'top',
2316
+ });
2317
+ }
2318
+ if (stat.label) {
2319
+ slide.addText(stat.label, {
2320
+ x: x + 0.15, y: cardY + 1.4, w: cardW - 0.3, h: 0.3,
2321
+ fontSize: 12, bold: true, color: labelColor, fontFace: FONTS.body, valign: 'top',
2322
+ });
2323
+ }
2324
+ if (props.showNotes !== false && stat.note) {
2325
+ slide.addText(stat.note, {
2326
+ x: x + 0.15, y: cardY + 1.72, w: cardW - 0.3, h: 0.25,
2327
+ fontSize: 10, color: subColor, fontFace: FONTS.mono, valign: 'top',
2328
+ });
2329
+ }
2330
+ });
2331
+ }
2332
+ if (props.footnote) {
2333
+ slide.addText(props.footnote, {
2334
+ x: 0.65, y: 4.6, w: 8.7, h: 0.3,
2335
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono, valign: 'top',
2336
+ });
2337
+ }
2338
+ addTheme07GlowLine(slide);
2339
+ }
2340
+ export function renderTheme07StatChartV1(slide, props) {
2341
+ if (props.kicker) {
2342
+ addTheme07Kicker(slide, props.kicker);
2343
+ }
2344
+ slide.addText(props.title ?? '', {
2345
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
2346
+ fontSize: 32, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
2347
+ });
2348
+ if (props.subtitle) {
2349
+ slide.addText(props.subtitle, {
2350
+ x: 0.65, y: 1.6, w: 8.7, h: 0.4,
2351
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2352
+ });
2353
+ }
2354
+ // 左侧结论数字
2355
+ slide.addText(props.number ?? '', {
2356
+ x: 0.65, y: 2.35, w: 3.4, h: 1.8,
2357
+ fontSize: 96, bold: true, fontFace: FONTS.heading, color: COLORS.accent, valign: 'top',
2358
+ });
2359
+ if (props.unit) {
2360
+ slide.addText(props.unit, {
2361
+ x: 0.65, y: 4.1, w: 3.4, h: 0.4,
2362
+ fontSize: 20, bold: true, fontFace: FONTS.heading, color: COLORS.secondary, valign: 'top',
2363
+ });
2364
+ }
2365
+ if (props.label) {
2366
+ slide.addText(props.label, {
2367
+ x: 0.65, y: 4.55, w: 3.4, h: 0.4,
2368
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2369
+ });
2370
+ }
2371
+ // 右侧柱状序列
2372
+ const series = (props.series || [])
2373
+ .filter((s) => s && s.label != null)
2374
+ .slice(0, 8);
2375
+ if (series.length > 0) {
2376
+ const chartX = 4.5;
2377
+ const chartY = 2.45;
2378
+ const chartW = 4.5;
2379
+ const chartH = 2.0;
2380
+ const maxValue = Math.max(1, ...series.map((s) => Number(s.value) || 0));
2381
+ const slotW = chartW / series.length;
2382
+ const barW = slotW * 0.6;
2383
+ const points = [];
2384
+ series.forEach((item, idx) => {
2385
+ const value = Number(item.value) || 0;
2386
+ const h = Math.max(0.05, (value / maxValue) * chartH);
2387
+ const x = chartX + idx * slotW + (slotW - barW) / 2;
2388
+ const y = chartY + chartH - h;
2389
+ const focus = idx === (props.focusIndex ?? 0);
2390
+ slide.addShape('rect', {
2391
+ x, y, w: barW, h,
2392
+ fill: { color: focus ? resolveTheme07CssColor('var(--lp-accent-cool)', COLORS.accent) : COLORS.accent, transparency: focus ? 0 : 25 },
2393
+ line: { type: 'none' },
2394
+ });
2395
+ points.push({ x: x + barW / 2, y });
2396
+ if (props.showValues !== false) {
2397
+ slide.addText(`${item.value ?? 0}`, {
2398
+ x, y: y - 0.32, w: barW, h: 0.3,
2399
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center', valign: 'top',
2400
+ });
2401
+ }
2402
+ slide.addText(`${item.label ?? ''}`, {
2403
+ x: chartX + idx * slotW, y: chartY + chartH + 0.06, w: slotW, h: 0.3,
2404
+ fontSize: 9, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center', valign: 'top',
2405
+ });
2406
+ });
2407
+ // 趋势线(连接柱顶中点)
2408
+ if (props.showTrend !== false && points.length > 1) {
2409
+ const trendColor = resolveTheme07CssColor('var(--lp-accent-2)', COLORS.accent2);
2410
+ for (let i = 0; i < points.length - 1; i++) {
2411
+ slide.addShape('line', {
2412
+ x1: points[i].x, y1: points[i].y, x2: points[i + 1].x, y2: points[i + 1].y,
2413
+ line: { color: trendColor, width: 1.5, transparency: 20 },
2414
+ });
2415
+ }
2416
+ }
2417
+ if (props.chartCaption) {
2418
+ slide.addText(props.chartCaption, {
2419
+ x: chartX, y: chartY + chartH + 0.4, w: chartW, h: 0.3,
2420
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono, valign: 'top',
2421
+ });
2422
+ }
2423
+ }
2424
+ addTheme07GlowLine(slide);
2425
+ }
2426
+ export function renderTheme07StatCompareV1(slide, props) {
2427
+ if (props.kicker) {
2428
+ addTheme07Kicker(slide, props.kicker);
2429
+ }
2430
+ slide.addText(props.title ?? '', {
2431
+ x: 0.65, y: 0.95, w: 8.7, h: 0.7,
2432
+ fontSize: 32, bold: true, fontFace: FONTS.heading, color: COLORS.primary, valign: 'top',
2433
+ });
2434
+ if (props.subtitle) {
2435
+ slide.addText(props.subtitle, {
2436
+ x: 0.65, y: 1.6, w: 8.7, h: 0.4,
2437
+ fontSize: 14, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2438
+ });
2439
+ }
2440
+ const focusSide = props.focusSide ?? 'right';
2441
+ const cardY = 2.3;
2442
+ const cardW = 3.7;
2443
+ const cardH = 2.0;
2444
+ const sides = [
2445
+ { data: props.left ?? {}, focus: focusSide === 'left', x: 0.65 },
2446
+ { data: props.right ?? {}, focus: focusSide === 'right', x: 5.65 },
2447
+ ];
2448
+ sides.forEach((side) => {
2449
+ addTheme07Card(slide, side.x, cardY, cardW, cardH, 0.08, side.focus ? COLORS.accent : COLORS.white);
2450
+ const valueColor = side.focus ? COLORS.white : COLORS.accent;
2451
+ const subColor = side.focus ? 'D0E0F0' : COLORS.secondary;
2452
+ const labelColor = side.focus ? COLORS.white : COLORS.primary;
2453
+ slide.addText(`${side.data.value ?? ''}`, {
2454
+ x: side.x + 0.2, y: cardY + 0.35, w: cardW - 0.4, h: 0.9,
2455
+ fontSize: 58, bold: true, fontFace: FONTS.heading, color: valueColor, valign: 'top',
2456
+ });
2457
+ if (side.data.unit) {
2458
+ slide.addText(side.data.unit, {
2459
+ x: side.x + 0.2, y: cardY + 1.25, w: cardW - 0.4, h: 0.3,
2460
+ fontSize: 16, color: subColor, fontFace: FONTS.mono, valign: 'top',
2461
+ });
2462
+ }
2463
+ if (side.data.label) {
2464
+ slide.addText(side.data.label, {
2465
+ x: side.x + 0.2, y: cardY + 1.6, w: cardW - 0.4, h: 0.3,
2466
+ fontSize: 12, bold: true, color: labelColor, fontFace: FONTS.body, valign: 'top',
2467
+ });
2468
+ }
2469
+ });
2470
+ // 中轴
2471
+ if (props.showAxis !== false) {
2472
+ slide.addShape('line', {
2473
+ x1: 5.0, y1: cardY, x2: 5.0, y2: cardY + cardH,
2474
+ line: { color: COLORS.border, width: 1, transparency: 50 },
2475
+ });
2476
+ }
2477
+ // 差值徽标
2478
+ if (props.showDelta !== false && props.delta) {
2479
+ slide.addText(props.delta, {
2480
+ x: 4.25, y: 2.95, w: 1.5, h: 0.5,
2481
+ fontSize: 24, bold: true, color: resolveTheme07CssColor('var(--lp-accent-cool)', COLORS.accentCool ?? COLORS.accent), fontFace: FONTS.heading, align: 'center', valign: 'middle',
2482
+ });
2483
+ if (props.deltaLabel) {
2484
+ slide.addText(props.deltaLabel, {
2485
+ x: 4.2, y: 3.5, w: 1.6, h: 0.3,
2486
+ fontSize: 10, color: COLORS.secondary, fontFace: FONTS.mono, align: 'center', valign: 'top',
2487
+ });
2488
+ }
2489
+ }
2490
+ if (props.caption) {
2491
+ slide.addText(props.caption, {
2492
+ x: 0.65, y: 4.55, w: 8.7, h: 0.35,
2493
+ fontSize: 13, color: COLORS.secondary, fontFace: FONTS.body, valign: 'top',
2494
+ });
2495
+ }
2496
+ addTheme07GlowLine(slide);
2497
+ }
2498
+ export function registerTheme07Renderers(registerPptxLayoutRenderer) {
2499
+ registerPptxLayoutRenderer('theme07_cover_v1', renderTheme07CoverV1);
2500
+ registerPptxLayoutRenderer('theme07_table_of_contents_v1', renderTheme07TableOfContentsV1);
2501
+ registerPptxLayoutRenderer('theme07_chapter_v1', renderTheme07ChapterV1);
2502
+ registerPptxLayoutRenderer('theme07_chapter_capital_v1', renderTheme07ChapterCapitalV1);
2503
+ registerPptxLayoutRenderer('theme07_chapter_risk_v1', renderTheme07ChapterRiskV1);
2504
+ registerPptxLayoutRenderer('theme07_chapter_appendix_v1', renderTheme07ChapterAppendixV1);
2505
+ registerPptxLayoutRenderer('theme07_content_v1', renderTheme07ContentV1);
2506
+ registerPptxLayoutRenderer('theme07_summary_v1', renderTheme07SummaryV1);
2507
+ registerPptxLayoutRenderer('theme07_ranking_v1', renderTheme07RankingV1);
2508
+ registerPptxLayoutRenderer('theme07_case_v1', renderTheme07CaseV1);
2509
+ registerPptxLayoutRenderer('theme07_case_grid_v1', renderTheme07CaseV1);
2510
+ registerPptxLayoutRenderer('theme07_sources_v1', renderTheme07SourcesV1);
2511
+ registerPptxLayoutRenderer('theme07_method_v1', renderTheme07MethodV1);
2512
+ registerPptxLayoutRenderer('theme07_monthly_v1', renderTheme07MonthlyV1);
2513
+ registerPptxLayoutRenderer('theme07_waterfall_v1', renderTheme07WaterfallV1);
2514
+ registerPptxLayoutRenderer('theme07_matrix_v1', renderTheme07MatrixV1);
2515
+ registerPptxLayoutRenderer('theme07_risk_v1', renderTheme07RiskV1);
2516
+ registerPptxLayoutRenderer('theme07_cover_lean_v1', renderTheme07CoverLeanV1);
2517
+ registerPptxLayoutRenderer('theme07_cover_supply_chain_v1', renderTheme07CoverSupplyChainV1);
2518
+ registerPptxLayoutRenderer('theme07_cover_retail_trend_v1', renderTheme07CoverRetailTrendV1);
2519
+ registerPptxLayoutRenderer('theme07_cover_supply_strategy_v1', renderTheme07CoverSupplyStrategyV1);
2520
+ registerPptxLayoutRenderer('theme07_peak_v1', renderTheme07PeakV1);
2521
+ registerPptxLayoutRenderer('theme07_cooldown_v1', renderTheme07CooldownV1);
2522
+ registerPptxLayoutRenderer('theme07_peak_trough_v1', renderTheme07PeakTroughV1);
2523
+ registerPptxLayoutRenderer('theme07_deal_size_v1', renderTheme07DealSizeV1);
2524
+ registerPptxLayoutRenderer('theme07_avg_ticket_v1', renderTheme07AvgTicketV1);
2525
+ registerPptxLayoutRenderer('theme07_outlook_v1', renderTheme07OutlookV1);
2526
+ registerPptxLayoutRenderer('theme07_repricing_v1', renderTheme07RepricingV1);
2527
+ registerPptxLayoutRenderer('theme07_deal_map_v1', renderTheme07DealMapV1);
2528
+ registerPptxLayoutRenderer('theme07_cold_start_v1', renderTheme07ColdStartV1);
2529
+ registerPptxLayoutRenderer('theme07_accelerate_v1', renderTheme07AccelerateV1);
2530
+ registerPptxLayoutRenderer('theme07_investor_v1', renderTheme07InvestorV1);
2531
+ registerPptxLayoutRenderer('theme07_active_capital_v1', renderTheme07ActiveCapitalV1);
2532
+ registerPptxLayoutRenderer('theme07_concentration_v1', renderTheme07ConcentrationV1);
2533
+ registerPptxLayoutRenderer('theme07_syndicate_v1', renderTheme07SyndicateV1);
2534
+ registerPptxLayoutRenderer('theme07_company_openai_v1', renderTheme07CompanyV1);
2535
+ registerPptxLayoutRenderer('theme07_company_figure_v1', renderTheme07CompanyV1);
2536
+ registerPptxLayoutRenderer('theme07_company_ssi_v1', renderTheme07CompanyV1);
2537
+ registerPptxLayoutRenderer('theme07_geo_center_v1', renderTheme07GeoV1);
2538
+ registerPptxLayoutRenderer('theme07_region_cluster_v1', renderTheme07GeoV1);
2539
+ registerPptxLayoutRenderer('theme07_resource_triad_v1', renderTheme07GeoV1);
2540
+ registerPptxLayoutRenderer('theme07_quote_v1', renderTheme07ClosingV1);
2541
+ registerPptxLayoutRenderer('theme07_closing_v1', renderTheme07ClosingV1);
2542
+ registerPptxLayoutRenderer('theme07_closing_quote_v1', renderTheme07ClosingQuoteV1);
2543
+ registerPptxLayoutRenderer('theme07_forward_v1', renderTheme07ClosingV1);
2544
+ registerPptxLayoutRenderer('theme07_about_lab_v1', renderTheme07ClosingV1);
2545
+ registerPptxLayoutRenderer('theme07_stat_hero_v1', renderTheme07StatHeroV1);
2546
+ registerPptxLayoutRenderer('theme07_stat_row_v1', renderTheme07StatRowV1);
2547
+ registerPptxLayoutRenderer('theme07_stat_chart_v1', renderTheme07StatChartV1);
2548
+ registerPptxLayoutRenderer('theme07_stat_compare_v1', renderTheme07StatCompareV1);
2549
+ // 行业纵深版式(P 批次):统一复用通用 sector 渲染器,字段与 Theme07SectorLayoutProps 一致
2550
+ registerPptxLayoutRenderer('theme07_knowledge_v1', renderTheme07SectorV1);
2551
+ registerPptxLayoutRenderer('theme07_legal_v1', renderTheme07SectorV1);
2552
+ registerPptxLayoutRenderer('theme07_healthcare_v1', renderTheme07SectorV1);
2553
+ registerPptxLayoutRenderer('theme07_finance_v1', renderTheme07SectorV1);
2554
+ registerPptxLayoutRenderer('theme07_compute_v1', renderTheme07SectorV1);
2555
+ registerPptxLayoutRenderer('theme07_chip_v1', renderTheme07SectorV1);
2556
+ registerPptxLayoutRenderer('theme07_robotics_v1', renderTheme07SectorV1);
2557
+ registerPptxLayoutRenderer('theme07_autonomy_v1', renderTheme07SectorV1);
2558
+ registerPptxLayoutRenderer('theme07_safety_v1', renderTheme07SectorV1);
2559
+ registerPptxLayoutRenderer('theme07_content_gen_v1', renderTheme07SectorV1);
2560
+ registerPptxLayoutRenderer('theme07_education_v1', renderTheme07SectorV1);
2561
+ registerPptxLayoutRenderer('theme07_support_v1', renderTheme07SectorV1);
2562
+ registerPptxLayoutRenderer('theme07_sales_v1', renderTheme07SectorV1);
2563
+ registerPptxLayoutRenderer('theme07_low_code_v1', renderTheme07SectorV1);
2564
+ registerPptxLayoutRenderer('theme07_open_source_v1', renderTheme07SectorV1);
2565
+ registerPptxLayoutRenderer('theme07_alignment_v1', renderTheme07SectorV1);
2566
+ registerPptxLayoutRenderer('theme07_early_stage_v1', renderTheme07SectorV1);
2567
+ registerPptxLayoutRenderer('theme07_deal_structure_v1', renderTheme07SectorV1);
2568
+ registerPptxLayoutRenderer('theme07_investor_mix_v1', renderTheme07SectorV1);
2569
+ registerPptxLayoutRenderer('theme07_resource_v1', renderTheme07SectorV1);
2570
+ registerPptxLayoutRenderer('theme07_alliance_v1', renderTheme07SectorV1);
2571
+ registerPptxLayoutRenderer('theme07_ecosystem_v1', renderTheme07SectorV1);
2572
+ registerPptxLayoutRenderer('theme07_revenue_v1', renderTheme07SectorV1);
2573
+ registerPptxLayoutRenderer('theme07_compliance_v1', renderTheme07SectorV1);
2574
+ registerPptxLayoutRenderer('theme07_margin_v1', renderTheme07SectorV1);
2575
+ registerPptxLayoutRenderer('theme07_moat_v1', renderTheme07SectorV1);
2576
+ registerPptxLayoutRenderer('theme07_strategy_infra_v1', renderTheme07SectorV1);
2577
+ registerPptxLayoutRenderer('theme07_strategy_vertical_v1', renderTheme07SectorV1);
2578
+ }
2579
+ //# sourceMappingURL=theme07-pptx.js.map