@cyber-dash-tech/revela 0.19.8 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -54
- package/README.zh-CN.md +36 -53
- package/designs/lucent/DESIGN.md +2 -0
- package/designs/lucent/design.css +43 -7
- package/designs/lucent-dark/DESIGN.md +2 -0
- package/designs/lucent-dark/design.css +55 -14
- package/designs/monet/DESIGN.md +2 -0
- package/designs/monet/design.css +79 -13
- package/designs/starter/DESIGN.md +2 -0
- package/designs/starter/design.css +51 -12
- package/designs/summit/DESIGN.md +2 -0
- package/designs/summit/design.css +75 -11
- package/lib/deck-html/foundation.ts +16 -2
- package/lib/design/designs.ts +13 -1
- package/lib/page-templates/built-in-preview.html +102 -41
- package/lib/page-templates/render.ts +123 -8
- package/lib/page-templates/templates/free.ts +3 -0
- package/lib/page-templates/templates/index.ts +2 -0
- package/lib/page-templates/templates/team.ts +3 -0
- package/lib/page-templates/vocabulary.ts +15 -0
- package/lib/runtime/index.ts +95 -3
- package/lib/runtime/open-deck.ts +190 -0
- package/package.json +1 -1
- package/plugins/revela/.codex-plugin/plugin.json +4 -3
- package/plugins/revela/mcp/revela-server.ts +17 -6
- package/plugins/revela/skills/revela/SKILL.md +1 -1
- package/plugins/revela/skills/revela-design/SKILL.md +5 -4
- package/plugins/revela/skills/revela-helper/SKILL.md +1 -1
- package/plugins/revela/skills/revela-review/SKILL.md +57 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<div class="slide-canvas">
|
|
13
13
|
<div class="template-frame template-hero template-hero--cover">
|
|
14
14
|
<div data-template-slot="hero"><header>
|
|
15
|
-
<p class="template-eyebrow">Template 01 /
|
|
15
|
+
<p class="template-eyebrow">Template 01 / 19</p>
|
|
16
16
|
<h1 class="template-title template-hero-title">cover</h1>
|
|
17
17
|
</header></div>
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
<div class="slide-canvas">
|
|
25
25
|
<div class="template-frame template-hero template-hero--section-divider">
|
|
26
26
|
<div data-template-slot="hero"><header>
|
|
27
|
-
<p class="template-eyebrow">Template 02 /
|
|
27
|
+
<p class="template-eyebrow">Template 02 / 19</p>
|
|
28
28
|
<h1 class="template-title template-hero-title">section-divider</h1>
|
|
29
29
|
</header></div>
|
|
30
30
|
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
<div class="slide-canvas">
|
|
37
37
|
<div class="template-frame template-hero template-hero--closing">
|
|
38
38
|
<div data-template-slot="hero"><header>
|
|
39
|
-
<p class="template-eyebrow">Template 03 /
|
|
39
|
+
<p class="template-eyebrow">Template 03 / 19</p>
|
|
40
40
|
<h1 class="template-title template-hero-title">closing</h1>
|
|
41
41
|
</header></div>
|
|
42
42
|
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
<div class="template-body template-agenda-panel" data-template-slot="agenda">
|
|
51
51
|
<div class="template-agenda-inner">
|
|
52
52
|
<div class="template-agenda-header">
|
|
53
|
-
<p class="template-eyebrow">Template 04 /
|
|
53
|
+
<p class="template-eyebrow">Template 04 / 19</p>
|
|
54
54
|
<h1 class="template-title">agenda</h1>
|
|
55
55
|
<p class="template-agenda-footer">Structure-First-Design</p>
|
|
56
56
|
</div>
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
<div class="slide-canvas">
|
|
67
67
|
<div class="template-frame">
|
|
68
68
|
<header>
|
|
69
|
-
<p class="template-eyebrow">Template 05 /
|
|
69
|
+
<p class="template-eyebrow">Template 05 / 19</p>
|
|
70
70
|
<h1 class="template-title">executive-summary</h1>
|
|
71
71
|
</header><div class="template-body template-grid cols-3" data-template-slot="summary-cards"><article class="template-card"><h2>Decision is ready</h2><p>The facts support moving from discussion to selection without adding another analysis cycle.</p><figure class="template-visual-placeholder"><div class="template-visual-placeholder-frame"><span class="template-visual-placeholder-label">image / chart slot (optional)</span></div></figure></article><article class="template-card"><h2>Risk is bounded</h2><p>Known caveats are visible, named, and can be managed through rollout gates.</p><figure class="template-visual-placeholder"><div class="template-visual-placeholder-frame"><span class="template-visual-placeholder-label">image / chart slot (optional)</span></div></figure></article><article class="template-card"><h2>Next step is narrow</h2><p>A pilot decision creates more learning without overcommitting capital or team capacity.</p><figure class="template-visual-placeholder"><div class="template-visual-placeholder-frame"><span class="template-visual-placeholder-label">image / chart slot (optional)</span></div></figure></article></div>
|
|
72
72
|
|
|
@@ -74,23 +74,67 @@
|
|
|
74
74
|
<div class="template-page-number">05</div>
|
|
75
75
|
</div>
|
|
76
76
|
</section>
|
|
77
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="6" data-design="built-in-preview" data-template="
|
|
77
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="6" data-design="built-in-preview" data-template="team">
|
|
78
78
|
<div class="slide-canvas">
|
|
79
79
|
<div class="template-frame">
|
|
80
80
|
<header>
|
|
81
|
-
<p class="template-eyebrow">Template 06 /
|
|
81
|
+
<p class="template-eyebrow">Template 06 / 19</p>
|
|
82
|
+
<h1 class="template-title">team</h1>
|
|
83
|
+
</header><div class="template-body"><div class="template-team-grid" data-template-slot="members"><article class="template-team-card">
|
|
84
|
+
<figure class="template-team-photo"><img src="./assets/card-lens.jpg" alt="Portrait placeholder"></figure>
|
|
85
|
+
<div class="template-team-copy">
|
|
86
|
+
<h2 class="template-team-name">Maya Chen</h2>
|
|
87
|
+
<p class="template-team-role">Product and AI systems</p>
|
|
88
|
+
<ul class="template-team-highlights"><li>Led the decision workspace launch from zero to enterprise pilot.</li><li>Built source-linked review loops for regulated teams.</li></ul>
|
|
89
|
+
<p class="template-team-education">M.S., Human-Computer Interaction</p>
|
|
90
|
+
</div>
|
|
91
|
+
</article><article class="template-team-card">
|
|
92
|
+
<figure class="template-team-photo"><img src="./assets/report-visual.jpg" alt="Portrait placeholder"></figure>
|
|
93
|
+
<div class="template-team-copy">
|
|
94
|
+
<h2 class="template-team-name">Jon Bell</h2>
|
|
95
|
+
<p class="template-team-role">Go-to-market and partnerships</p>
|
|
96
|
+
<ul class="template-team-highlights"><li>Scaled strategic accounts across finance and healthcare.</li><li>Opened channel partnerships with implementation teams.</li></ul>
|
|
97
|
+
<p class="template-team-education">MBA, Strategy and Operations</p>
|
|
98
|
+
</div>
|
|
99
|
+
</article><article class="template-team-card">
|
|
100
|
+
<figure class="template-team-photo"><img src="./assets/soft-texture.jpg" alt="Portrait placeholder"></figure>
|
|
101
|
+
<div class="template-team-copy">
|
|
102
|
+
<h2 class="template-team-name">Ari Patel</h2>
|
|
103
|
+
<p class="template-team-role">Data and platform engineering</p>
|
|
104
|
+
<ul class="template-team-highlights"><li>Architected reliable artifact generation and QA pipelines.</li><li>Shipped analytics systems used by executive teams.</li></ul>
|
|
105
|
+
<p class="template-team-education">B.S., Computer Science</p>
|
|
106
|
+
</div>
|
|
107
|
+
</article><article class="template-team-card">
|
|
108
|
+
<figure class="template-team-photo"><img src="./assets/toc-orb.png" alt="Portrait placeholder"></figure>
|
|
109
|
+
<div class="template-team-copy">
|
|
110
|
+
<h2 class="template-team-name">Lina Gomez</h2>
|
|
111
|
+
<p class="template-team-role">Research and narrative design</p>
|
|
112
|
+
<ul class="template-team-highlights"><li>Directed research synthesis for high-stakes board materials.</li><li>Designed traceable evidence models for complex decisions.</li></ul>
|
|
113
|
+
<p class="template-team-education">M.A., Communication Design</p>
|
|
114
|
+
</div>
|
|
115
|
+
</article></div></div>
|
|
116
|
+
|
|
117
|
+
</div>
|
|
118
|
+
<div class="template-page-number">06</div>
|
|
119
|
+
</div>
|
|
120
|
+
</section>
|
|
121
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="7" data-design="built-in-preview" data-template="problem-context">
|
|
122
|
+
<div class="slide-canvas">
|
|
123
|
+
<div class="template-frame">
|
|
124
|
+
<header>
|
|
125
|
+
<p class="template-eyebrow">Template 07 / 19</p>
|
|
82
126
|
<h1 class="template-title">problem-context</h1>
|
|
83
127
|
</header><div class="template-body template-grid cols-2"><div class="template-card" data-template-slot="context"><p>Use this template when the audience needs the situation, tension, and implication before seeing recommendations.</p></div><div class="template-card" data-template-slot="supporting-points"><ul class="template-list"><li><strong>Situation</strong> A shift has changed the operating baseline.</li><li><strong>Tension</strong> Current process cannot absorb the new variance cleanly.</li><li><strong>Implication</strong> Delay increases rework and weakens decision confidence.</li></ul></div></div>
|
|
84
128
|
|
|
85
129
|
</div>
|
|
86
|
-
<div class="template-page-number">
|
|
130
|
+
<div class="template-page-number">07</div>
|
|
87
131
|
</div>
|
|
88
132
|
</section>
|
|
89
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
133
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="8" data-design="built-in-preview" data-template="key-message-evidence">
|
|
90
134
|
<div class="slide-canvas">
|
|
91
135
|
<div class="template-frame">
|
|
92
136
|
<header>
|
|
93
|
-
<p class="template-eyebrow">Template
|
|
137
|
+
<p class="template-eyebrow">Template 08 / 19</p>
|
|
94
138
|
<h1 class="template-title">key-message-evidence</h1>
|
|
95
139
|
</header><div class="template-body template-grid cols-2"><div class="template-key-message-panel" data-template-slot="key-message">
|
|
96
140
|
<h2 class="template-key-message-kicker">Key message</h2>
|
|
@@ -98,14 +142,14 @@
|
|
|
98
142
|
</div><div class="template-evidence-grid" data-template-slot="evidence"><article class="template-card template-evidence-card"><h3>Evidence 1</h3><p>The generated HTML separates the key-message panel from the evidence grid, so the claim cannot collapse into generic card content.</p></article><article class="template-card template-evidence-card"><h3>Evidence 2</h3><p>Each evidence slot has a stable title and explanation area, giving the agent a predictable place for proof, caveat, or source-backed detail.</p></article><article class="template-card template-evidence-card"><h3>Evidence 3</h3><p>QA can inspect the DOM contract before visual styling, which keeps template structure from depending on a design skin.</p></article></div></div>
|
|
99
143
|
|
|
100
144
|
</div>
|
|
101
|
-
<div class="template-page-number">
|
|
145
|
+
<div class="template-page-number">08</div>
|
|
102
146
|
</div>
|
|
103
147
|
</section>
|
|
104
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
148
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="9" data-design="built-in-preview" data-template="claim-supporting-visual">
|
|
105
149
|
<div class="slide-canvas">
|
|
106
150
|
<div class="template-frame">
|
|
107
151
|
<header>
|
|
108
|
-
<p class="template-eyebrow">Template
|
|
152
|
+
<p class="template-eyebrow">Template 09 / 19</p>
|
|
109
153
|
<h1 class="template-title">claim-supporting-visual</h1>
|
|
110
154
|
</header><div class="template-body template-grid cols-2"><div class="template-claim-text-panel" data-template-slot="claim">
|
|
111
155
|
<h2 class="template-claim-text-title">A single visual should carry one argument.</h2>
|
|
@@ -114,14 +158,14 @@
|
|
|
114
158
|
</div><div class="template-chart-panel template-visual-slot-panel" data-template-slot="visual"><span class="template-visual-slot-label">image / chart slot (optional)</span></div></div>
|
|
115
159
|
|
|
116
160
|
</div>
|
|
117
|
-
<div class="template-page-number">
|
|
161
|
+
<div class="template-page-number">09</div>
|
|
118
162
|
</div>
|
|
119
163
|
</section>
|
|
120
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
164
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="10" data-design="built-in-preview" data-template="metric-highlight">
|
|
121
165
|
<div class="slide-canvas">
|
|
122
166
|
<div class="template-frame">
|
|
123
167
|
<header>
|
|
124
|
-
<p class="template-eyebrow">Template
|
|
168
|
+
<p class="template-eyebrow">Template 10 / 19</p>
|
|
125
169
|
<h1 class="template-title">metric-highlight</h1>
|
|
126
170
|
</header><div class="template-body"><div class="template-metric-layout template-metric-layout--insight-bottom"><div class="template-stat-grid" data-template-slot="metrics"><article class="template-card"><div class="template-stat-value">67%</div><h2>Adoption signal</h2><p>Primary number plus interpretation.</p></article><article class="template-card"><div class="template-stat-value">3x</div><h2>Review speed</h2><p>Comparison is stated beside the metric.</p></article><article class="template-card"><div class="template-stat-value">14d</div><h2>Pilot window</h2><p>Time bound keeps the ask concrete.</p></article></div><div class="template-insight-panel">
|
|
127
171
|
<h2 class="template-insight-title"><i class="template-insight-icon" data-lucide="scan-search" aria-hidden="true"></i><span>Read the signal</span></h2>
|
|
@@ -129,14 +173,14 @@
|
|
|
129
173
|
</div></div></div>
|
|
130
174
|
|
|
131
175
|
</div>
|
|
132
|
-
<div class="template-page-number">
|
|
176
|
+
<div class="template-page-number">10</div>
|
|
133
177
|
</div>
|
|
134
178
|
</section>
|
|
135
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
179
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="11" data-design="built-in-preview" data-template="chart-takeaways">
|
|
136
180
|
<div class="slide-canvas">
|
|
137
181
|
<div class="template-frame">
|
|
138
182
|
<header>
|
|
139
|
-
<p class="template-eyebrow">Template
|
|
183
|
+
<p class="template-eyebrow">Template 11 / 19</p>
|
|
140
184
|
<h1 class="template-title">chart-takeaways</h1>
|
|
141
185
|
</header><div class="template-body template-grid template-chart-layout"><div class="template-chart-panel template-visual-slot-panel" data-template-slot="visual"><span class="template-visual-slot-label">image / chart slot (optional)</span></div><div class="template-text-panel template-text-panel--color template-chart-takeaway-panel" data-template-slot="takeaways">
|
|
142
186
|
<h2 class="template-text-panel-title">What to read</h2>
|
|
@@ -145,26 +189,26 @@
|
|
|
145
189
|
</div></div>
|
|
146
190
|
|
|
147
191
|
</div>
|
|
148
|
-
<div class="template-page-number">
|
|
192
|
+
<div class="template-page-number">11</div>
|
|
149
193
|
</div>
|
|
150
194
|
</section>
|
|
151
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
195
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="12" data-design="built-in-preview" data-template="table">
|
|
152
196
|
<div class="slide-canvas">
|
|
153
197
|
<div class="template-frame">
|
|
154
198
|
<header>
|
|
155
|
-
<p class="template-eyebrow">Template
|
|
199
|
+
<p class="template-eyebrow">Template 12 / 19</p>
|
|
156
200
|
<h1 class="template-title">table</h1>
|
|
157
201
|
</header><div class="template-body"><div class="template-table-layout"><div class="template-side-panel template-text-panel template-text-panel--clear" data-template-slot="text-card"><h2 class="template-side-panel-title template-text-panel-title">Financial readout</h2><p class="template-side-panel-body template-text-panel-body">Read top-line growth first, then check margin, cash conversion, and retention to see whether the plan is financially durable.</p><blockquote class="template-text-panel-quote">Durability shows up when growth, margin, and cash all point in the same direction.</blockquote></div><div class="template-table-region" data-template-slot="table"><div class="template-table-wrap"><table class="template-table"><thead><tr><th>Line item</th><th>FY2025</th><th>FY2026 Plan</th><th>YoY / note</th></tr></thead><tbody><tr><td>Revenue</td><td>$84.2M</td><td>$104.8M</td><td>+24% planned growth</td></tr><tr><td>Gross margin</td><td>68.4%</td><td>71.2%</td><td>+280 bps mix shift</td></tr><tr><td>Operating expense</td><td>$42.7M</td><td>$49.1M</td><td>Scale hiring below revenue growth</td></tr><tr><td>EBITDA</td><td>$14.9M</td><td>$23.6M</td><td>+58% operating leverage</td></tr><tr><td>Free cash flow</td><td>$9.8M</td><td>$16.4M</td><td>Cash conversion improves to 69%</td></tr><tr><td>Net retention</td><td>116%</td><td>121%</td><td>Expansion supports plan quality</td></tr></tbody></table></div></div></div></div>
|
|
158
202
|
|
|
159
203
|
</div>
|
|
160
|
-
<div class="template-page-number">
|
|
204
|
+
<div class="template-page-number">12</div>
|
|
161
205
|
</div>
|
|
162
206
|
</section>
|
|
163
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
207
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="13" data-design="built-in-preview" data-template="table-comparison">
|
|
164
208
|
<div class="slide-canvas">
|
|
165
209
|
<div class="template-frame">
|
|
166
210
|
<header>
|
|
167
|
-
<p class="template-eyebrow">Template
|
|
211
|
+
<p class="template-eyebrow">Template 13 / 19</p>
|
|
168
212
|
<h1 class="template-title">table-comparison</h1>
|
|
169
213
|
</header><div class="template-body" data-template-slot="table"><div class="template-table-wrap"><table class="template-table"><thead><tr><th>Layer</th><th>Owns</th><th>Agent task</th></tr></thead><tbody><tr><td>Template</td><td>Structure and DOM contract</td><td>Select the page pattern</td></tr><tr><td>Content</td><td>Claim, evidence, caveat</td><td>Fill the meaning</td></tr><tr><td>Design</td><td>Color, type, surfaces</td><td>Skin stable classes</td></tr></tbody></table><div class="template-insight-panel">
|
|
170
214
|
<h2 class="template-insight-title"><i class="template-insight-icon" data-lucide="lightbulb" aria-hidden="true"></i><span>Insight</span></h2>
|
|
@@ -172,14 +216,14 @@
|
|
|
172
216
|
</div></div></div>
|
|
173
217
|
|
|
174
218
|
</div>
|
|
175
|
-
<div class="template-page-number">
|
|
219
|
+
<div class="template-page-number">13</div>
|
|
176
220
|
</div>
|
|
177
221
|
</section>
|
|
178
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
222
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="14" data-design="built-in-preview" data-template="milestone">
|
|
179
223
|
<div class="slide-canvas">
|
|
180
224
|
<div class="template-frame">
|
|
181
225
|
<header>
|
|
182
|
-
<p class="template-eyebrow">Template
|
|
226
|
+
<p class="template-eyebrow">Template 14 / 19</p>
|
|
183
227
|
<h1 class="template-title">milestone</h1>
|
|
184
228
|
</header><div class="template-body"><div class="template-timeline template-timeline--horizontal" data-template-slot="timeline" style="--timeline-count:5"><article class="template-timeline-item">
|
|
185
229
|
<div class="template-timeline-copy template-card">
|
|
@@ -224,14 +268,14 @@
|
|
|
224
268
|
</article></div></div>
|
|
225
269
|
|
|
226
270
|
</div>
|
|
227
|
-
<div class="template-page-number">
|
|
271
|
+
<div class="template-page-number">14</div>
|
|
228
272
|
</div>
|
|
229
273
|
</section>
|
|
230
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
274
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="15" data-design="built-in-preview" data-template="timeline">
|
|
231
275
|
<div class="slide-canvas">
|
|
232
276
|
<div class="template-frame">
|
|
233
277
|
<header>
|
|
234
|
-
<p class="template-eyebrow">Template
|
|
278
|
+
<p class="template-eyebrow">Template 15 / 19</p>
|
|
235
279
|
<h1 class="template-title">timeline</h1>
|
|
236
280
|
</header><div class="template-body"><div class="template-timeline-layout template-timeline-layout--left"><div class="template-side-panel template-text-panel template-text-panel--color" data-template-slot="insight"><h2 class="template-side-panel-title template-text-panel-title">Reading the journey</h2><p class="template-side-panel-body template-text-panel-body">The timeline should show sequence and decision rhythm, while the side panel explains why the milestones matter.</p><blockquote class="template-text-panel-quote">Sequence is evidence when each step changes what the audience can believe.</blockquote></div><div class="template-timeline template-timeline--vertical" data-template-slot="timeline" style="--timeline-count:4"><article class="template-timeline-item">
|
|
237
281
|
<span class="template-timeline-dot" aria-hidden="true"></span>
|
|
@@ -264,43 +308,60 @@
|
|
|
264
308
|
</article></div></div></div>
|
|
265
309
|
|
|
266
310
|
</div>
|
|
267
|
-
<div class="template-page-number">
|
|
311
|
+
<div class="template-page-number">15</div>
|
|
268
312
|
</div>
|
|
269
313
|
</section>
|
|
270
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
314
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="16" data-design="built-in-preview" data-template="process-steps">
|
|
271
315
|
<div class="slide-canvas">
|
|
272
316
|
<div class="template-frame">
|
|
273
317
|
<header>
|
|
274
|
-
<p class="template-eyebrow">Template
|
|
318
|
+
<p class="template-eyebrow">Template 16 / 19</p>
|
|
275
319
|
<h1 class="template-title">process-steps</h1>
|
|
276
320
|
</header><div class="template-body"><div class="template-steps" data-template-slot="steps"><article class="template-card"><div class="template-step-number">1</div><h2>Choose</h2><p>Select the page template that matches the communication job.</p><figure class="template-visual-placeholder"><div class="template-visual-placeholder-frame"><span class="template-visual-placeholder-label">image / chart slot (optional)</span></div></figure></article><article class="template-card"><div class="template-step-number">2</div><h2>Fill</h2><p>Provide only the content fields the template needs.</p><figure class="template-visual-placeholder"><div class="template-visual-placeholder-frame"><span class="template-visual-placeholder-label">image / chart slot (optional)</span></div></figure></article><article class="template-card"><div class="template-step-number">3</div><h2>Style</h2><p>Let the active design control type, color, and surfaces.</p><figure class="template-visual-placeholder"><div class="template-visual-placeholder-frame"><span class="template-visual-placeholder-label">image / chart slot (optional)</span></div></figure></article><article class="template-card"><div class="template-step-number">4</div><h2>QA</h2><p>Run contract and visual checks before export.</p><figure class="template-visual-placeholder"><div class="template-visual-placeholder-frame"><span class="template-visual-placeholder-label">image / chart slot (optional)</span></div></figure></article></div></div>
|
|
277
321
|
|
|
278
322
|
</div>
|
|
279
|
-
<div class="template-page-number">
|
|
323
|
+
<div class="template-page-number">16</div>
|
|
280
324
|
</div>
|
|
281
325
|
</section>
|
|
282
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
326
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="17" data-design="built-in-preview" data-template="recommendation-decision">
|
|
283
327
|
<div class="slide-canvas">
|
|
284
328
|
<div class="template-frame">
|
|
285
329
|
<header>
|
|
286
|
-
<p class="template-eyebrow">Template
|
|
330
|
+
<p class="template-eyebrow">Template 17 / 19</p>
|
|
287
331
|
<h1 class="template-title">recommendation-decision</h1>
|
|
288
332
|
</header><div class="template-body template-grid cols-3"><div class="template-card" data-template-slot="recommendation"><h2>Recommendation</h2><p>Adopt page templates as the structural layer, with designs remaining user-customizable.</p><figure class="template-image-card"><div class="template-image-frame"><img src="./assets/card-lens.jpg" alt="Lucent design asset"></div><figcaption class="template-image-caption">Design asset example</figcaption></figure></div><div data-template-slot="rationale"><article class="template-card"><h3>Rationale</h3><p>This keeps generation reliable while leaving style expressive and replaceable.</p></article></div><div class="template-card" data-template-slot="next-steps"><h2>Next steps</h2><ol class="template-list"><li><strong>Pilot</strong> Use the built-in preview to tune every template.</li><li><strong>Validate</strong> Promote only contracts that pass QA and browser review.</li><li><strong>Ship</strong> Document the add-slide workflow for agents.</li></ol></div></div>
|
|
289
333
|
|
|
290
334
|
</div>
|
|
291
|
-
<div class="template-page-number">
|
|
335
|
+
<div class="template-page-number">17</div>
|
|
292
336
|
</div>
|
|
293
337
|
</section>
|
|
294
|
-
<section class="slide template-slide" slide-qa="true" data-slide-index="
|
|
338
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="18" data-design="built-in-preview" data-template="risks-tradeoffs">
|
|
295
339
|
<div class="slide-canvas">
|
|
296
340
|
<div class="template-frame">
|
|
297
341
|
<header>
|
|
298
|
-
<p class="template-eyebrow">Template
|
|
342
|
+
<p class="template-eyebrow">Template 18 / 19</p>
|
|
299
343
|
<h1 class="template-title">risks-tradeoffs</h1>
|
|
300
344
|
</header><div class="template-body template-grid cols-3" data-template-slot="risks"><article class="template-card"><h3>Constraint</h3><p>Templates can over-constrain if they become decorative presets instead of communication jobs.</p><figure class="template-image-card"><div class="template-image-frame"><img src="./assets/report-visual.jpg" alt="Report visual"></div><figcaption class="template-image-caption">Design asset example</figcaption></figure></article><article class="template-card"><h3>Mitigation</h3><p>Keep bounded HTML edit flow after scaffold insertion so agents can improve the page directly.</p></article><article class="template-card"><h3>Tradeoff</h3><p>More structure improves QA, but only if template contracts stay small and semantic.</p></article></div>
|
|
301
345
|
|
|
302
346
|
</div>
|
|
303
|
-
<div class="template-page-number">
|
|
347
|
+
<div class="template-page-number">18</div>
|
|
348
|
+
</div>
|
|
349
|
+
</section>
|
|
350
|
+
<section class="slide template-slide" slide-qa="true" data-slide-index="19" data-design="built-in-preview" data-template="free">
|
|
351
|
+
<div class="slide-canvas">
|
|
352
|
+
<div class="template-frame">
|
|
353
|
+
<header>
|
|
354
|
+
<p class="template-eyebrow">Template 19 / 19</p>
|
|
355
|
+
<h1 class="template-title">free</h1>
|
|
356
|
+
</header><div class="template-body"><div class="template-free-stage" data-template-slot="placeholder"><section class="template-free-placeholder">
|
|
357
|
+
<span class="template-free-placeholder-label">placeholder</span>
|
|
358
|
+
<h2>Flexible content placeholder</h2>
|
|
359
|
+
<p>Agent may replace this single region with multiple images, charts, text blocks, tables, or a mixed composition.</p>
|
|
360
|
+
<div class="template-free-placeholder-hints"><span class="template-free-placeholder-hint">images</span><span class="template-free-placeholder-hint">charts</span><span class="template-free-placeholder-hint">text</span><span class="template-free-placeholder-hint">tables</span></div>
|
|
361
|
+
</section></div></div>
|
|
362
|
+
|
|
363
|
+
</div>
|
|
364
|
+
<div class="template-page-number">19</div>
|
|
304
365
|
</div>
|
|
305
366
|
</section>
|
|
306
367
|
<!-- revela-slides:end -->
|
|
@@ -7,7 +7,7 @@ export type PageTemplateStatus = "metadata-only" | "renderable"
|
|
|
7
7
|
|
|
8
8
|
export interface PageTemplateField {
|
|
9
9
|
name: string
|
|
10
|
-
type: "string" | "string[]" | "items[]" | "metrics[]" | "milestones[]" | "rows[]" | "steps[]"
|
|
10
|
+
type: "string" | "string[]" | "items[]" | "metrics[]" | "milestones[]" | "rows[]" | "steps[]" | "members[]" | "placeholder"
|
|
11
11
|
required?: boolean
|
|
12
12
|
description: string
|
|
13
13
|
}
|
|
@@ -112,6 +112,10 @@ const templates: PageTemplateDefinition[] = [
|
|
|
112
112
|
field("title", "string", "Slide title.", true),
|
|
113
113
|
field("items", "items[]", "Summary takeaways.", true),
|
|
114
114
|
], ["Use 3-4 takeaways.", "Each takeaway needs a short label and support line."], ["Contains summary cards."]),
|
|
115
|
+
define("team", "Team", "Introduce the people behind the work with portrait-led member cards.", [
|
|
116
|
+
field("title", "string", "Slide title.", true),
|
|
117
|
+
field("members", "members[]", "Team members with portrait, role, highlights, and education.", true),
|
|
118
|
+
], ["Use 3-4 members for a readable 16:9 page.", "Each member should have one portrait, two concise highlights, and one highest education line."], ["Contains team member cards.", "Each card keeps portrait and credentials distinct."]),
|
|
115
119
|
define("problem-context", "Problem / Context", "Frame why the topic matters now.", [
|
|
116
120
|
field("title", "string", "Slide title.", true),
|
|
117
121
|
field("body", "string", "Context paragraph.", true),
|
|
@@ -189,6 +193,10 @@ const templates: PageTemplateDefinition[] = [
|
|
|
189
193
|
field("title", "string", "Slide title.", true),
|
|
190
194
|
field("items", "items[]", "Risks or caveats.", true),
|
|
191
195
|
], ["Name uncertainty instead of hiding it."], ["Contains risk/tradeoff cards."]),
|
|
196
|
+
define("free", "Free / Plain", "Start from a title and one flexible placeholder that can later hold images, charts, text, or mixed content.", [
|
|
197
|
+
field("title", "string", "Slide title.", true),
|
|
198
|
+
field("placeholder", "placeholder", "One flexible placeholder region for agent-decided content composition.", true),
|
|
199
|
+
], ["Use for pages that need a simple title and one replaceable working area.", "The placeholder may later contain multiple images, charts, text blocks, tables, or mixed content selected by the agent."], ["Contains one free placeholder stage.", "The single placeholder remains visible and replaceable."]),
|
|
192
200
|
]
|
|
193
201
|
|
|
194
202
|
export function listPageTemplates(): { ok: true; templates: PageTemplateDefinition[] } {
|
|
@@ -241,6 +249,15 @@ export function builtInPreviewFixtures(): BuiltInPreviewFixture[] {
|
|
|
241
249
|
{ label: "Next step is narrow", description: "A pilot decision creates more learning without overcommitting capital or team capacity." },
|
|
242
250
|
],
|
|
243
251
|
}),
|
|
252
|
+
fixture("team", {
|
|
253
|
+
title: "team",
|
|
254
|
+
members: [
|
|
255
|
+
{ name: "Maya Chen", role: "Product and AI systems", image: "./assets/card-lens.jpg", imageAlt: "Portrait placeholder", highlights: ["Led the decision workspace launch from zero to enterprise pilot.", "Built source-linked review loops for regulated teams."], education: "M.S., Human-Computer Interaction" },
|
|
256
|
+
{ name: "Jon Bell", role: "Go-to-market and partnerships", image: "./assets/report-visual.jpg", imageAlt: "Portrait placeholder", highlights: ["Scaled strategic accounts across finance and healthcare.", "Opened channel partnerships with implementation teams."], education: "MBA, Strategy and Operations" },
|
|
257
|
+
{ name: "Ari Patel", role: "Data and platform engineering", image: "./assets/soft-texture.jpg", imageAlt: "Portrait placeholder", highlights: ["Architected reliable artifact generation and QA pipelines.", "Shipped analytics systems used by executive teams."], education: "B.S., Computer Science" },
|
|
258
|
+
{ name: "Lina Gomez", role: "Research and narrative design", image: "./assets/toc-orb.png", imageAlt: "Portrait placeholder", highlights: ["Directed research synthesis for high-stakes board materials.", "Designed traceable evidence models for complex decisions."], education: "M.A., Communication Design" },
|
|
259
|
+
],
|
|
260
|
+
}),
|
|
244
261
|
fixture("problem-context", {
|
|
245
262
|
title: "problem-context",
|
|
246
263
|
body: "Use this template when the audience needs the situation, tension, and implication before seeing recommendations.",
|
|
@@ -371,6 +388,14 @@ export function builtInPreviewFixtures(): BuiltInPreviewFixture[] {
|
|
|
371
388
|
{ label: "Tradeoff", description: "More structure improves QA, but only if template contracts stay small and semantic." },
|
|
372
389
|
],
|
|
373
390
|
}),
|
|
391
|
+
fixture("free", {
|
|
392
|
+
title: "free",
|
|
393
|
+
placeholder: {
|
|
394
|
+
label: "Flexible content placeholder",
|
|
395
|
+
description: "Agent may replace this single region with multiple images, charts, text blocks, tables, or a mixed composition.",
|
|
396
|
+
hints: ["images", "charts", "text", "tables"],
|
|
397
|
+
},
|
|
398
|
+
}),
|
|
374
399
|
]
|
|
375
400
|
}
|
|
376
401
|
|
|
@@ -475,23 +500,23 @@ export function templateDeckCss(input: { designName?: string; designAssetBasePat
|
|
|
475
500
|
const lucentCoverBackground = designName === "lucent" && assetBasePath ? cssUrl(`${assetBasePath}/cover-background.jpg`) : ""
|
|
476
501
|
const lucentClosingBackground = designName === "lucent" && assetBasePath ? cssUrl(`${assetBasePath}/closing-background.jpg`) : ""
|
|
477
502
|
const lucentCoverBackgroundCss = lucentCoverBackground ? `
|
|
478
|
-
.template-slide[data-
|
|
503
|
+
.template-slide[data-template="cover"] .slide-canvas {
|
|
479
504
|
background:
|
|
480
505
|
linear-gradient(90deg, rgba(7,17,31,0.82), rgba(7,17,31,0.42) 52%, rgba(7,17,31,0.24)),
|
|
481
506
|
url("${lucentCoverBackground}") center center / cover no-repeat;
|
|
482
507
|
}
|
|
483
|
-
.template-slide[data-
|
|
508
|
+
.template-slide[data-template="agenda"] .slide-canvas {
|
|
484
509
|
background:
|
|
485
510
|
linear-gradient(90deg, rgba(7,17,31,0.86), rgba(7,17,31,0.58) 52%, rgba(7,17,31,0.32)),
|
|
486
511
|
url("${lucentCoverBackground}") center center / cover no-repeat;
|
|
487
512
|
}
|
|
488
|
-
.template-slide[data-
|
|
513
|
+
.template-slide[data-template="section-divider"] .slide-canvas {
|
|
489
514
|
background:
|
|
490
515
|
linear-gradient(90deg, rgba(7,17,31,0.86), rgba(16,26,43,0.62) 58%, rgba(36,58,115,0.36)),
|
|
491
516
|
url("${lucentCoverBackground}") center center / cover no-repeat;
|
|
492
517
|
}` : ""
|
|
493
518
|
const lucentClosingBackgroundCss = lucentClosingBackground ? `
|
|
494
|
-
.template-slide[data-
|
|
519
|
+
.template-slide[data-template="closing"] .slide-canvas {
|
|
495
520
|
background:
|
|
496
521
|
linear-gradient(90deg, rgba(7,17,31,0.82), rgba(49,94,234,0.42) 58%, rgba(24,168,216,0.24)),
|
|
497
522
|
url("${lucentClosingBackground}") center center / cover no-repeat;
|
|
@@ -591,10 +616,13 @@ ${lucentClosingBackgroundCss}
|
|
|
591
616
|
.template-text-panel-formula-caption { margin: 0; font-size: 14px; line-height: 1.35; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); }
|
|
592
617
|
.template-text-panel--color .template-text-panel-formula-caption { color: rgba(255,255,255,0.72); }
|
|
593
618
|
.template-chart-takeaway-list { display: grid; gap: 22px; width: 100%; }
|
|
594
|
-
.template-chart-takeaway-item { display: grid; gap: 7px; padding-top: 18px; border-top: 1px solid
|
|
619
|
+
.template-chart-takeaway-item { display: grid; gap: 7px; padding-top: 18px; border-top: 1px solid var(--line); }
|
|
620
|
+
.template-text-panel--color .template-chart-takeaway-item { border-top-color: rgba(255,255,255,0.24); }
|
|
595
621
|
.template-chart-takeaway-item:first-child { padding-top: 0; border-top: 0; }
|
|
596
|
-
.template-chart-takeaway-item h3 { margin: 0; font-size: 25px; line-height: 1.24; color:
|
|
597
|
-
.template-chart-takeaway-item
|
|
622
|
+
.template-chart-takeaway-item h3 { margin: 0; font-size: 25px; line-height: 1.24; color: var(--text-primary); }
|
|
623
|
+
.template-text-panel--color .template-chart-takeaway-item h3 { color: white; }
|
|
624
|
+
.template-chart-takeaway-item p { margin: 0; font-size: 20px; line-height: 1.46; color: var(--text-secondary); }
|
|
625
|
+
.template-text-panel--color .template-chart-takeaway-item p { color: rgba(255,255,255,0.78); }
|
|
598
626
|
.template-bar { flex: 1; background: linear-gradient(180deg, var(--accent-primary), var(--accent-cyan)); min-height: 80px; }
|
|
599
627
|
.template-table-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 34px; height: 100%; align-items: stretch; }
|
|
600
628
|
.template-table-layout .template-side-panel { grid-column: 1; grid-row: 1; }
|
|
@@ -652,6 +680,25 @@ ${lucentClosingBackgroundCss}
|
|
|
652
680
|
.template-timeline--vertical .template-timeline-item:nth-child(even) .template-timeline-copy { grid-column: 3; text-align: left; align-self: center; }
|
|
653
681
|
.template-steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px; }
|
|
654
682
|
.template-step-number { font-size: 48px; color: var(--accent-primary); font-weight: 800; margin-bottom: 30px; }
|
|
683
|
+
.template-team-grid { height: 100%; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; align-items: stretch; }
|
|
684
|
+
.template-team-card { min-width: 0; min-height: 0; display: grid; grid-template-rows: 330px minmax(0, 1fr); overflow: hidden; background: rgba(255,255,255,0.86); border: 1px solid var(--line); border-radius: var(--surface-radius); box-shadow: 0 18px 44px var(--shadow-soft); }
|
|
685
|
+
.template-team-photo { margin: 0; width: 100%; height: 100%; overflow: hidden; background: linear-gradient(135deg, var(--accent-soft), rgba(24,168,216,0.16)); display: grid; place-items: center; }
|
|
686
|
+
.template-team-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
687
|
+
.template-team-photo span { font-family: var(--font-display); font-size: 72px; line-height: 1; color: var(--accent-primary); font-weight: 800; }
|
|
688
|
+
.template-team-copy { min-height: 0; display: flex; flex-direction: column; gap: 12px; padding: 26px; }
|
|
689
|
+
.template-team-name { margin: 0; font-size: 30px; line-height: 1.18; color: var(--text-primary); padding-bottom: 3px; overflow: visible; }
|
|
690
|
+
.template-team-role { margin: 0; font-size: 15px; line-height: 1.35; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent-primary); font-weight: 800; }
|
|
691
|
+
.template-team-highlights { margin: 4px 0 0; padding: 0; list-style: none; display: grid; gap: 9px; }
|
|
692
|
+
.template-team-highlights li { position: relative; padding-left: 18px; font-size: 17px; line-height: 1.36; color: var(--text-secondary); }
|
|
693
|
+
.template-team-highlights li::before { content: ""; position: absolute; left: 0; top: 9px; width: 6px; height: 6px; background: var(--accent-primary); border-radius: 999px; }
|
|
694
|
+
.template-team-education { margin: auto 0 0; padding-top: 14px; border-top: 1px solid var(--line); font-size: 14px; line-height: 1.35; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); font-weight: 800; }
|
|
695
|
+
.template-free-stage { height: 100%; display: grid; grid-template-columns: minmax(0, 1fr); }
|
|
696
|
+
.template-free-placeholder { min-width: 0; min-height: 0; display: flex; flex-direction: column; justify-content: flex-end; gap: 16px; padding: 42px; border: 1px dashed var(--line-strong); border-radius: var(--surface-radius); background: linear-gradient(135deg, rgba(49,94,234,0.06), rgba(24,168,216,0.07)); overflow: hidden; }
|
|
697
|
+
.template-free-placeholder-label { align-self: flex-start; font-size: 13px; line-height: 1; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-primary); font-weight: 800; }
|
|
698
|
+
.template-free-placeholder h2 { margin: 0; font-size: 38px; line-height: 1.18; color: var(--text-primary); padding-bottom: 4px; overflow: visible; }
|
|
699
|
+
.template-free-placeholder p { margin: 0; max-width: 980px; font-size: 23px; line-height: 1.42; color: var(--text-secondary); }
|
|
700
|
+
.template-free-placeholder-hints { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; }
|
|
701
|
+
.template-free-placeholder-hint { display: inline-flex; align-items: center; min-height: 32px; padding: 7px 12px; border: 1px solid var(--line); border-radius: 999px; font-size: 13px; line-height: 1; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); font-weight: 800; background: rgba(255,255,255,0.58); }
|
|
655
702
|
.template-image-card { width: 100%; margin: 18px 0 0; display: grid; gap: 8px; }
|
|
656
703
|
.template-image-frame { width: 100%; height: 128px; border-radius: var(--surface-radius); overflow: hidden; background: var(--surface-tint, #f1f6fc); border: 1px solid var(--line); }
|
|
657
704
|
.template-image-frame img { display: block; width: 100%; height: 100%; object-fit: cover; }
|
|
@@ -731,6 +778,20 @@ ${lucentClosingBackgroundCss}
|
|
|
731
778
|
.template-frame--catalog .template-timeline-copy p:last-child { font-size: 15px; line-height: 1.24; }
|
|
732
779
|
.template-frame--catalog .template-steps { gap: 16px; }
|
|
733
780
|
.template-frame--catalog .template-step-number { font-size: 40px; margin-bottom: 20px; }
|
|
781
|
+
.template-frame--catalog .template-team-grid { gap: 16px; }
|
|
782
|
+
.template-frame--catalog .template-team-card { grid-template-rows: 230px minmax(0, 1fr); }
|
|
783
|
+
.template-frame--catalog .template-team-copy { padding: 18px; gap: 8px; }
|
|
784
|
+
.template-frame--catalog .template-team-name { font-size: 22px; line-height: 1.14; }
|
|
785
|
+
.template-frame--catalog .template-team-role { font-size: 11px; line-height: 1.25; }
|
|
786
|
+
.template-frame--catalog .template-team-highlights { gap: 6px; }
|
|
787
|
+
.template-frame--catalog .template-team-highlights li { font-size: 13px; line-height: 1.25; padding-left: 14px; }
|
|
788
|
+
.template-frame--catalog .template-team-highlights li::before { top: 7px; width: 5px; height: 5px; }
|
|
789
|
+
.template-frame--catalog .template-team-education { font-size: 10px; line-height: 1.25; padding-top: 9px; }
|
|
790
|
+
.template-frame--catalog .template-free-placeholder { padding: 28px; gap: 10px; }
|
|
791
|
+
.template-frame--catalog .template-free-placeholder-label { font-size: 10px; }
|
|
792
|
+
.template-frame--catalog .template-free-placeholder h2 { font-size: 28px; line-height: 1.16; }
|
|
793
|
+
.template-frame--catalog .template-free-placeholder p { font-size: 17px; line-height: 1.3; }
|
|
794
|
+
.template-frame--catalog .template-free-placeholder-hint { min-height: 26px; padding: 6px 9px; font-size: 10px; }
|
|
734
795
|
.template-frame--catalog .template-image-frame { height: 86px; }
|
|
735
796
|
.template-frame--catalog .template-image-caption { font-size: 11px; }
|
|
736
797
|
.template-frame--catalog .template-visual-placeholder-frame { height: 110px; }
|
|
@@ -1005,6 +1066,7 @@ function renderBody(templateId: string, content: Record<string, any>): string {
|
|
|
1005
1066
|
if (["cover", "section-divider", "closing"].includes(templateId)) return `<div data-template-slot="hero">${renderHeader(content, templateId, { hero: true })}</div>`
|
|
1006
1067
|
if (templateId === "agenda") return renderAgenda(content)
|
|
1007
1068
|
if (templateId === "executive-summary") return `${renderHeader(content, "Executive Summary")}<div class="template-body template-grid cols-3" data-template-slot="summary-cards">${cards(items(content), "h2", { visualPlaceholder: true })}</div>`
|
|
1069
|
+
if (templateId === "team") return `${renderHeader(content, "Team")}<div class="template-body"><div class="template-team-grid" data-template-slot="members">${teamCards(content.members)}</div></div>`
|
|
1008
1070
|
if (templateId === "problem-context") return `${renderHeader(content, "Problem / Context")}<div class="template-body template-grid cols-2"><div class="template-card" data-template-slot="context"><p>${escapeHtml(stringValue(content.body))}</p></div><div class="template-card" data-template-slot="supporting-points">${list(items(content))}</div></div>`
|
|
1009
1071
|
if (templateId === "key-message-evidence") return `${renderHeader(content, "Key Message + Evidence")}<div class="template-body template-grid cols-2">${keyMessagePanel(content)}<div class="template-evidence-grid" data-template-slot="evidence">${evidenceCards(items(content))}</div></div>`
|
|
1010
1072
|
if (templateId === "claim-supporting-visual") return `${renderHeader(content, "Claim + Supporting Visual")}<div class="template-body template-grid cols-2">${claimTextPanel(content)}${visualSlotPanel()}</div>`
|
|
@@ -1018,6 +1080,7 @@ function renderBody(templateId: string, content: Record<string, any>): string {
|
|
|
1018
1080
|
if (templateId === "process-steps") return `${renderHeader(content, "Process / Steps")}<div class="template-body"><div class="template-steps" data-template-slot="steps">${steps(content.steps)}</div></div>`
|
|
1019
1081
|
if (templateId === "recommendation-decision") return `${renderHeader(content, "Recommendation / Decision")}<div class="template-body template-grid cols-3"><div class="template-card" data-template-slot="recommendation"><h2>Recommendation</h2><p>${escapeHtml(stringValue(content.recommendation))}</p>${imageCard(content)}</div><div data-template-slot="rationale">${cards(items(content).slice(0, 1), "h3")}</div><div class="template-card" data-template-slot="next-steps"><h2>Next steps</h2>${orderedSteps(content.steps)}</div></div>`
|
|
1020
1082
|
if (templateId === "risks-tradeoffs") return `${renderHeader(content, "Risks / Tradeoffs")}<div class="template-body template-grid cols-3" data-template-slot="risks">${cards(items(content), "h3")}</div>`
|
|
1083
|
+
if (templateId === "free") return `${renderHeader(content, "Free / Plain")}<div class="template-body"><div class="template-free-stage" data-template-slot="placeholder">${freePlaceholder(content.placeholder ?? content.placeholders)}</div></div>`
|
|
1021
1084
|
return renderHeader(content, templateId)
|
|
1022
1085
|
}
|
|
1023
1086
|
|
|
@@ -1056,6 +1119,45 @@ function evidenceCards(items: Array<{ label: string; description: string; image?
|
|
|
1056
1119
|
return items.map((item, index) => `<article class="template-card template-evidence-card"><h3>${escapeHtml(item.label || `Evidence ${index + 1}`)}</h3><p>${escapeHtml(item.description)}</p>${imageCard(item)}</article>`).join("")
|
|
1057
1120
|
}
|
|
1058
1121
|
|
|
1122
|
+
function teamCards(input: any): string {
|
|
1123
|
+
const members = Array.isArray(input) ? input : []
|
|
1124
|
+
return members.slice(0, 6).map((member, index) => {
|
|
1125
|
+
const name = stringValue(member?.name) || `Member ${index + 1}`
|
|
1126
|
+
const role = stringValue(member?.role || member?.title)
|
|
1127
|
+
const image = safeImagePath(stringValue(member?.image))
|
|
1128
|
+
const alt = stringValue(member?.imageAlt) || name
|
|
1129
|
+
const highlights = stringArray(member?.highlights).slice(0, 3)
|
|
1130
|
+
const education = stringValue(member?.education || member?.highestEducation)
|
|
1131
|
+
return `<article class="template-team-card">
|
|
1132
|
+
<figure class="template-team-photo">${image ? `<img src="${escapeAttribute(image)}" alt="${escapeAttribute(alt)}">` : `<span>${escapeHtml(initials(name))}</span>`}</figure>
|
|
1133
|
+
<div class="template-team-copy">
|
|
1134
|
+
<h2 class="template-team-name">${escapeHtml(name)}</h2>
|
|
1135
|
+
${role ? `<p class="template-team-role">${escapeHtml(role)}</p>` : ""}
|
|
1136
|
+
${highlights.length > 0 ? `<ul class="template-team-highlights">${highlights.map((item) => `<li>${escapeHtml(item)}</li>`).join("")}</ul>` : ""}
|
|
1137
|
+
${education ? `<p class="template-team-education">${escapeHtml(education)}</p>` : ""}
|
|
1138
|
+
</div>
|
|
1139
|
+
</article>`
|
|
1140
|
+
}).join("")
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
function freePlaceholder(input: any): string {
|
|
1144
|
+
const legacy = Array.isArray(input) ? input : []
|
|
1145
|
+
const value = legacy.length > 0 ? {
|
|
1146
|
+
label: "Flexible content placeholder",
|
|
1147
|
+
description: "Agent may replace this single region with multiple images, charts, text blocks, tables, or a mixed composition.",
|
|
1148
|
+
hints: legacy.map((item) => stringValue(item?.type || item?.label)).filter(Boolean),
|
|
1149
|
+
} : input
|
|
1150
|
+
const label = stringValue(value?.label) || "Flexible content placeholder"
|
|
1151
|
+
const description = stringValue(value?.description) || "Agent may decide whether this placeholder becomes multiple images, charts, text blocks, tables, or a mixed composition."
|
|
1152
|
+
const hints = stringArray(value?.hints || value?.accepts).slice(0, 6)
|
|
1153
|
+
return `<section class="template-free-placeholder">
|
|
1154
|
+
<span class="template-free-placeholder-label">placeholder</span>
|
|
1155
|
+
<h2>${escapeHtml(label)}</h2>
|
|
1156
|
+
<p>${escapeHtml(description)}</p>
|
|
1157
|
+
${hints.length > 0 ? `<div class="template-free-placeholder-hints">${hints.map((hint) => `<span class="template-free-placeholder-hint">${escapeHtml(hint)}</span>`).join("")}</div>` : ""}
|
|
1158
|
+
</section>`
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1059
1161
|
function chartTakeawayPanel(content: Record<string, any>): string {
|
|
1060
1162
|
const takeawayItems = items(content)
|
|
1061
1163
|
const title = stringValue(content.takeawaysTitle) || "What to read"
|
|
@@ -1227,6 +1329,12 @@ function items(content: Record<string, any>): Array<{ label: string; description
|
|
|
1227
1329
|
}))
|
|
1228
1330
|
}
|
|
1229
1331
|
|
|
1332
|
+
function stringArray(value: any): string[] {
|
|
1333
|
+
if (Array.isArray(value)) return value.map(stringValue).filter(Boolean)
|
|
1334
|
+
const single = stringValue(value)
|
|
1335
|
+
return single ? [single] : []
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1230
1338
|
function scaffoldSeed(templateId: string, seed: Record<string, any>): Record<string, any> {
|
|
1231
1339
|
const title = stringValue(seed.title) || getPageTemplate(templateId).title
|
|
1232
1340
|
const base = { ...seed, title }
|
|
@@ -1235,6 +1343,7 @@ function scaffoldSeed(templateId: string, seed: Record<string, any>): Record<str
|
|
|
1235
1343
|
if (templateId === "closing") return { ...base }
|
|
1236
1344
|
if (templateId === "agenda") return { items: defaultItems(["Situation", "Evidence", "Decision"]), ...base }
|
|
1237
1345
|
if (templateId === "executive-summary") return { items: defaultItems(["Decision is ready", "Risk is bounded", "Next step is narrow"]), ...base }
|
|
1346
|
+
if (templateId === "team") return { members: [{ name: "Member One", role: "Role or function", highlights: ["Replace with a standout project.", "Replace with a standout experience."], education: "Highest education" }, { name: "Member Two", role: "Role or function", highlights: ["Replace with a standout project.", "Replace with a standout experience."], education: "Highest education" }, { name: "Member Three", role: "Role or function", highlights: ["Replace with a standout project.", "Replace with a standout experience."], education: "Highest education" }], ...base }
|
|
1238
1347
|
if (templateId === "problem-context") return { body: "Replace with context, tension, and why now.", items: defaultItems(["Context", "Implication"]), ...base }
|
|
1239
1348
|
if (templateId === "key-message-evidence") return { body: "Replace with the key message the audience should remember.", items: defaultItems(["Evidence 1", "Evidence 2", "Evidence 3"]), ...base }
|
|
1240
1349
|
if (templateId === "claim-supporting-visual") return { claim: "Replace with one visual claim.", body: "Use this copy to guide how the visual should be read.", items: defaultItems(["Anchor", "Callout"]), ...base }
|
|
@@ -1247,6 +1356,7 @@ function scaffoldSeed(templateId: string, seed: Record<string, any>): Record<str
|
|
|
1247
1356
|
if (templateId === "process-steps") return { steps: defaultItems(["Step 1", "Step 2", "Step 3"]), ...base }
|
|
1248
1357
|
if (templateId === "recommendation-decision") return { recommendation: "Replace with the recommended decision.", items: defaultItems(["Rationale"]), steps: defaultItems(["Pilot", "Validate", "Ship"]), ...base }
|
|
1249
1358
|
if (templateId === "risks-tradeoffs") return { items: defaultItems(["Risk", "Tradeoff", "Mitigation"]), ...base }
|
|
1359
|
+
if (templateId === "free") return { placeholder: { label: "Flexible content placeholder", description: "Replace this single region with one or more images, charts, text blocks, tables, or mixed content.", hints: ["images", "charts", "text", "tables"] }, ...base }
|
|
1250
1360
|
return base
|
|
1251
1361
|
}
|
|
1252
1362
|
|
|
@@ -1295,6 +1405,11 @@ function safeImagePath(value: string): string {
|
|
|
1295
1405
|
return image
|
|
1296
1406
|
}
|
|
1297
1407
|
|
|
1408
|
+
function initials(value: string): string {
|
|
1409
|
+
const parts = value.split(/\s+/).filter(Boolean)
|
|
1410
|
+
return parts.slice(0, 2).map((part) => part.charAt(0).toUpperCase()).join("") || "?"
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1298
1413
|
function escapeHtml(value: string): string {
|
|
1299
1414
|
return value
|
|
1300
1415
|
.replace(/&/g, "&")
|