@blockslides/ai-context 0.1.5 → 0.2.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.
@@ -0,0 +1,739 @@
1
+ import { blocks, slide, type SlideNode } from "./schemaBuilder";
2
+
3
+ export type PresetKey =
4
+ | "tpl.titleAndSubheader"
5
+ | "tpl.imageAndText"
6
+ | "tpl.textAndImage"
7
+ | "tpl.twoColumns"
8
+ | "tpl.twoColumnsWithHeader"
9
+ | "tpl.threeColumns"
10
+ | "tpl.threeColumnsWithHeader"
11
+ | "tpl.fourColumns"
12
+ | "tpl.fourColumnsWithHeader"
13
+ | "tpl.titleWithBullets"
14
+ | "tpl.titleBulletsAndImage"
15
+ | "tpl.twoImageColumns"
16
+ | "tpl.accentLeft"
17
+ | "tpl.accentRight"
18
+ | "tpl.accentTop"
19
+ | "tpl.accentRightFit"
20
+ | "tpl.accentLeftFit"
21
+ | "tpl.fullImage";
22
+
23
+ type PresetTemplate = {
24
+ key: PresetKey;
25
+ label: string;
26
+ description?: string;
27
+ icon?: string;
28
+ build: () => SlideNode;
29
+ };
30
+
31
+ const titleAndSubheaderIcon =
32
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="18" y="22" width="60" height="12" rx="2" fill="#D4D4D8"/><rect x="26" y="38" width="44" height="8" rx="2" fill="#E5E7EB"/></svg>';
33
+
34
+ const titleAndSubheader: PresetTemplate = {
35
+ key: "tpl.titleAndSubheader",
36
+ label: "Title & Subheader",
37
+ description: "Centered title and subtitle for a new presentation",
38
+ icon: titleAndSubheaderIcon,
39
+ build: () =>
40
+ slide.singleCol({
41
+ rowAttrs: { className: "min-h-[720px] items-center justify-center" },
42
+ columnAttrs: {
43
+ verticalAlign: "center",
44
+ horizontalAlign: "center",
45
+ className: "gap-6 p-12 text-center bg-white",
46
+ },
47
+ content: [
48
+ blocks.heading("Lorem ipsum dolor sit amet", 1),
49
+ blocks.paragraph("Consectetur adipiscing elit. Sed do eiusmod tempor incididunt."),
50
+ ],
51
+ }),
52
+ };
53
+
54
+ const imageTextIcon =
55
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="16" y="26" width="24" height="16" rx="2" fill="#E5E7EB"/><rect x="21" y="31" width="14" height="6" rx="1" fill="#D4D4D8"/><rect x="46" y="24" width="34" height="6" rx="1.5" fill="#D4D4D8"/><rect x="46" y="33" width="34" height="5" rx="1.5" fill="#E5E7EB"/><rect x="46" y="41" width="28" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
56
+
57
+ const textImageIcon =
58
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="18" y="24" width="34" height="6" rx="1.5" fill="#D4D4D8"/><rect x="18" y="33" width="34" height="5" rx="1.5" fill="#E5E7EB"/><rect x="18" y="41" width="28" height="5" rx="1.5" fill="#E5E7EB"/><rect x="56" y="26" width="24" height="16" rx="2" fill="#E5E7EB"/><rect x="61" y="31" width="14" height="6" rx="1" fill="#D4D4D8"/></svg>';
59
+
60
+ const twoColumnsIcon =
61
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="18" y="22" width="26" height="6" rx="1.5" fill="#D4D4D8"/><rect x="18" y="31" width="26" height="5" rx="1.5" fill="#E5E7EB"/><rect x="18" y="39" width="22" height="5" rx="1.5" fill="#E5E7EB"/><rect x="52" y="22" width="26" height="6" rx="1.5" fill="#D4D4D8"/><rect x="52" y="31" width="26" height="5" rx="1.5" fill="#E5E7EB"/><rect x="52" y="39" width="22" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
62
+
63
+ const twoColumnsHeaderIcon =
64
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="18" y="18" width="60" height="6" rx="1.5" fill="#D4D4D8"/><rect x="18" y="28" width="26" height="6" rx="1.5" fill="#D4D4D8"/><rect x="18" y="37" width="26" height="5" rx="1.5" fill="#E5E7EB"/><rect x="18" y="45" width="22" height="5" rx="1.5" fill="#E5E7EB"/><rect x="52" y="28" width="26" height="6" rx="1.5" fill="#D4D4D8"/><rect x="52" y="37" width="26" height="5" rx="1.5" fill="#E5E7EB"/><rect x="52" y="45" width="22" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
65
+
66
+ const threeColumnsIcon =
67
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="14" y="22" width="20" height="6" rx="1.5" fill="#D4D4D8"/><rect x="14" y="31" width="20" height="5" rx="1.5" fill="#E5E7EB"/><rect x="14" y="39" width="18" height="5" rx="1.5" fill="#E5E7EB"/><rect x="38" y="22" width="20" height="6" rx="1.5" fill="#D4D4D8"/><rect x="38" y="31" width="20" height="5" rx="1.5" fill="#E5E7EB"/><rect x="38" y="39" width="18" height="5" rx="1.5" fill="#E5E7EB"/><rect x="62" y="22" width="20" height="6" rx="1.5" fill="#D4D4D8"/><rect x="62" y="31" width="20" height="5" rx="1.5" fill="#E5E7EB"/><rect x="62" y="39" width="18" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
68
+
69
+ const threeColumnsHeaderIcon =
70
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="16" y="16" width="60" height="6" rx="1.5" fill="#D4D4D8"/><rect x="14" y="28" width="20" height="6" rx="1.5" fill="#D4D4D8"/><rect x="14" y="37" width="20" height="5" rx="1.5" fill="#E5E7EB"/><rect x="14" y="45" width="18" height="5" rx="1.5" fill="#E5E7EB"/><rect x="38" y="28" width="20" height="6" rx="1.5" fill="#D4D4D8"/><rect x="38" y="37" width="20" height="5" rx="1.5" fill="#E5E7EB"/><rect x="38" y="45" width="18" height="5" rx="1.5" fill="#E5E7EB"/><rect x="62" y="28" width="20" height="6" rx="1.5" fill="#D4D4D8"/><rect x="62" y="37" width="20" height="5" rx="1.5" fill="#E5E7EB"/><rect x="62" y="45" width="18" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
71
+
72
+ const fourColumnsHeaderIcon =
73
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="16" y="16" width="60" height="6" rx="1.5" fill="#D4D4D8"/><rect x="12" y="28" width="16" height="6" rx="1.5" fill="#D4D4D8"/><rect x="12" y="37" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="12" y="45" width="14" height="5" rx="1.5" fill="#E5E7EB"/><rect x="32" y="28" width="16" height="6" rx="1.5" fill="#D4D4D8"/><rect x="32" y="37" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="32" y="45" width="14" height="5" rx="1.5" fill="#E5E7EB"/><rect x="52" y="28" width="16" height="6" rx="1.5" fill="#D4D4D8"/><rect x="52" y="37" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="52" y="45" width="14" height="5" rx="1.5" fill="#E5E7EB"/><rect x="72" y="28" width="16" height="6" rx="1.5" fill="#D4D4D8"/><rect x="72" y="37" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="72" y="45" width="14" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
74
+
75
+ const fourColumnsIcon =
76
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="12" y="22" width="16" height="6" rx="1.5" fill="#D4D4D8"/><rect x="12" y="31" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="12" y="39" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="32" y="22" width="16" height="6" rx="1.5" fill="#D4D4D8"/><rect x="32" y="31" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="32" y="39" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="52" y="22" width="16" height="6" rx="1.5" fill="#D4D4D8"/><rect x="52" y="31" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="52" y="39" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="72" y="22" width="16" height="6" rx="1.5" fill="#D4D4D8"/><rect x="72" y="31" width="16" height="5" rx="1.5" fill="#E5E7EB"/><rect x="72" y="39" width="16" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
77
+
78
+ const fullImageIcon =
79
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="14" y="14" width="68" height="44" rx="3" fill="#E5E7EB"/><path d="M18 50 34 32l12 14 8-10 16 14H18Z" fill="#D4D4D8"/><circle cx="32" cy="26" r="4" fill="#D4D4D8"/></svg>';
80
+
81
+ const twoImageColumnsIcon =
82
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="16" y="18" width="64" height="6" rx="1.5" fill="#D4D4D8"/><rect x="16" y="28" width="28" height="14" rx="2" fill="#E5E7EB"/><rect x="52" y="28" width="28" height="14" rx="2" fill="#E5E7EB"/><rect x="16" y="46" width="20" height="4" rx="1" fill="#D4D4D8"/><rect x="52" y="46" width="20" height="4" rx="1" fill="#D4D4D8"/></svg>';
83
+
84
+ const accentLeftIcon =
85
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="12" y="18" width="20" height="36" rx="2" fill="#EFEFEF"/><rect x="18" y="30" width="8" height="8" rx="1" fill="#CCCCCC"/><rect x="36" y="26" width="42" height="6" rx="1.5" fill="#D4D4D8"/><rect x="36" y="36" width="38" height="5" rx="1.5" fill="#E5E7EB"/><rect x="36" y="44" width="32" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
86
+
87
+ const accentRightIcon =
88
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="64" y="18" width="20" height="36" rx="2" fill="#EFEFEF"/><rect x="70" y="30" width="8" height="8" rx="1" fill="#CCCCCC"/><rect x="16" y="26" width="42" height="6" rx="1.5" fill="#D4D4D8"/><rect x="16" y="36" width="38" height="5" rx="1.5" fill="#E5E7EB"/><rect x="16" y="44" width="32" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
89
+
90
+ const accentTopIcon =
91
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="14" y="14" width="68" height="16" rx="2" fill="#EFEFEF"/><rect x="44" y="18" width="8" height="8" rx="1" fill="#CCCCCC"/><rect x="18" y="36" width="60" height="6" rx="1.5" fill="#D4D4D8"/><rect x="18" y="46" width="56" height="5" rx="1.5" fill="#E5E7EB"/><rect x="18" y="54" width="48" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
92
+
93
+ const accentRightFitIcon =
94
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="64" y="24" width="16" height="20" rx="2" fill="#E5E7EB"/><rect x="68" y="28" width="8" height="8" rx="1" fill="#CCCCCC"/><rect x="14" y="28" width="44" height="6" rx="1.5" fill="#D4D4D8"/><rect x="14" y="38" width="40" height="5" rx="1.5" fill="#E5E7EB"/><rect x="14" y="46" width="32" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
95
+
96
+ const accentLeftFitIcon =
97
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="16" y="24" width="16" height="20" rx="2" fill="#E5E7EB"/><rect x="20" y="28" width="8" height="8" rx="1" fill="#CCCCCC"/><rect x="36" y="28" width="44" height="6" rx="1.5" fill="#D4D4D8"/><rect x="36" y="38" width="40" height="5" rx="1.5" fill="#E5E7EB"/><rect x="36" y="46" width="32" height="5" rx="1.5" fill="#E5E7EB"/></svg>';
98
+
99
+ const titleBulletsIcon =
100
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="18" y="20" width="60" height="6" rx="1.5" fill="#D4D4D8"/><circle cx="22" cy="32" r="2" fill="#D4D4D8"/><rect x="28" y="30" width="44" height="4" rx="1" fill="#E5E7EB"/><circle cx="22" cy="39" r="2" fill="#D4D4D8"/><rect x="28" y="37" width="44" height="4" rx="1" fill="#E5E7EB"/><circle cx="22" cy="46" r="2" fill="#D4D4D8"/><rect x="28" y="44" width="36" height="4" rx="1" fill="#E5E7EB"/></svg>';
101
+
102
+ const titleBulletsImageIcon =
103
+ '<svg width="96" height="72" viewBox="0 0 96 72" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="6" y="6" width="84" height="60" rx="4" stroke="#D4D4D8" stroke-width="2" fill="#F9FAFB"/><rect x="16" y="18" width="64" height="6" rx="1.5" fill="#D4D4D8"/><circle cx="20" cy="31" r="2" fill="#D4D4D8"/><rect x="26" y="29" width="24" height="4" rx="1" fill="#E5E7EB"/><circle cx="20" cy="38" r="2" fill="#D4D4D8"/><rect x="26" y="36" width="24" height="4" rx="1" fill="#E5E7EB"/><circle cx="20" cy="45" r="2" fill="#D4D4D8"/><rect x="26" y="43" width="20" height="4" rx="1" fill="#E5E7EB"/><rect x="56" y="31" width="24" height="16" rx="2" fill="#E5E7EB"/><rect x="61" y="36" width="14" height="6" rx="1" fill="#D4D4D8"/></svg>';
104
+ const imageAndText: PresetTemplate = {
105
+ key: "tpl.imageAndText",
106
+ label: "Image & Text",
107
+ description: "Image on left, text on right",
108
+ icon: imageTextIcon,
109
+ build: () =>
110
+ slide.twoCol({
111
+ rowAttrs: { className: "items-center" },
112
+ leftColumnAttrs: {
113
+ horizontalAlign: "center",
114
+ verticalAlign: "center",
115
+ className: "p-8",
116
+ },
117
+ rightColumnAttrs: {
118
+ verticalAlign: "center",
119
+ className: "p-8 gap-3",
120
+ },
121
+ left: [
122
+ blocks.imageBlock({
123
+ src: "https://placehold.co/640x480/png",
124
+ layout: "contain",
125
+ fullBleed: false,
126
+ }),
127
+ ],
128
+ right: [
129
+ blocks.heading("Lorem ipsum dolor sit amet", 2),
130
+ blocks.paragraph("Consectetur adipiscing elit. Sed do eiusmod tempor incididunt."),
131
+ blocks.paragraph("Ut enim ad minim veniam, quis nostrud exercitation."),
132
+ ],
133
+ }),
134
+ };
135
+
136
+ const textAndImage: PresetTemplate = {
137
+ key: "tpl.textAndImage",
138
+ label: "Text & Image",
139
+ description: "Text on left, image on right",
140
+ icon: textImageIcon,
141
+ build: () =>
142
+ slide.twoCol({
143
+ rowAttrs: { className: "items-center" },
144
+ leftColumnAttrs: {
145
+ verticalAlign: "center",
146
+ className: "p-8 gap-3",
147
+ },
148
+ rightColumnAttrs: {
149
+ horizontalAlign: "center",
150
+ verticalAlign: "center",
151
+ className: "p-8",
152
+ },
153
+ left: [
154
+ blocks.heading("Lorem ipsum dolor sit amet", 2),
155
+ blocks.paragraph("Consectetur adipiscing elit. Sed do eiusmod tempor incididunt."),
156
+ blocks.paragraph("Ut enim ad minim veniam, quis nostrud exercitation."),
157
+ ],
158
+ right: [
159
+ blocks.imageBlock({
160
+ src: "https://placehold.co/640x480/png",
161
+ layout: "contain",
162
+ fullBleed: false,
163
+ }),
164
+ ],
165
+ }),
166
+ };
167
+
168
+ const twoColumns: PresetTemplate = {
169
+ key: "tpl.twoColumns",
170
+ label: "Two Columns",
171
+ description: "Header above two balanced text columns",
172
+ icon: twoColumnsIcon,
173
+ build: () =>
174
+ slide.singleCol({
175
+ columnAttrs: { className: "w-full p-6 gap-4", horizontalAlign: "stretch" },
176
+ content: [
177
+ blocks.heading("Section heading", 2),
178
+ {
179
+ type: "row",
180
+ attrs: { layout: "1-1", className: "items-start w-full gap-4" },
181
+ content: [
182
+ {
183
+ type: "column",
184
+ attrs: { className: "p-4 gap-3 w-full box-border" },
185
+ content: [
186
+ blocks.paragraph("Lorem ipsum dolor sit amet."),
187
+ blocks.paragraph("Consectetur adipiscing elit. Sed do eiusmod tempor incididunt."),
188
+ blocks.paragraph("Ut enim ad minim veniam, quis nostrud exercitation."),
189
+ ],
190
+ },
191
+ {
192
+ type: "column",
193
+ attrs: { className: "p-4 gap-3 w-full box-border" },
194
+ content: [
195
+ blocks.paragraph("Lorem ipsum dolor sit amet."),
196
+ blocks.paragraph("Consectetur adipiscing elit. Sed do eiusmod tempor incididunt."),
197
+ blocks.paragraph("Ut enim ad minim veniam, quis nostrud exercitation."),
198
+ ],
199
+ },
200
+ ],
201
+ },
202
+ ],
203
+ }),
204
+ };
205
+
206
+ const twoColumnsWithHeader: PresetTemplate = {
207
+ key: "tpl.twoColumnsWithHeader",
208
+ label: "Two Columns + Header",
209
+ description: "Header plus two columns, each with its own heading",
210
+ icon: twoColumnsHeaderIcon,
211
+ build: () =>
212
+ slide.singleCol({
213
+ columnAttrs: { className: "w-full p-6 gap-4", horizontalAlign: "stretch" },
214
+ content: [
215
+ blocks.heading("Section heading", 2),
216
+ {
217
+ type: "row",
218
+ attrs: { layout: "1-1", className: "items-start w-full gap-4" },
219
+ content: [
220
+ {
221
+ type: "column",
222
+ attrs: { className: "p-4 gap-3 w-full box-border" },
223
+ content: [
224
+ blocks.heading("Column heading", 4),
225
+ blocks.paragraph("Consectetur adipiscing elit. Sed do eiusmod tempor incididunt."),
226
+ blocks.paragraph("Ut enim ad minim veniam, quis nostrud exercitation."),
227
+ ],
228
+ },
229
+ {
230
+ type: "column",
231
+ attrs: { className: "p-4 gap-3 w-full box-border" },
232
+ content: [
233
+ blocks.heading("Column heading", 4),
234
+ blocks.paragraph("Consectetur adipiscing elit. Sed do eiusmod tempor incididunt."),
235
+ blocks.paragraph("Ut enim ad minim veniam, quis nostrud exercitation."),
236
+ ],
237
+ },
238
+ ],
239
+ },
240
+ ],
241
+ }),
242
+ };
243
+
244
+ const threeColumns: PresetTemplate = {
245
+ key: "tpl.threeColumns",
246
+ label: "Three Columns",
247
+ description: "Balanced three-column text",
248
+ icon: threeColumnsIcon,
249
+ build: () =>
250
+ slide.singleCol({
251
+ columnAttrs: { className: "w-full p-6 gap-4", horizontalAlign: "stretch" },
252
+ content: [
253
+ {
254
+ type: "row",
255
+ attrs: { layout: "1-1-1", className: "items-start w-full gap-4" },
256
+ content: [
257
+ {
258
+ type: "column",
259
+ attrs: { className: "p-3 gap-3 w-full box-border" },
260
+ content: [
261
+ blocks.paragraph("Lorem ipsum dolor sit amet."),
262
+ blocks.paragraph("Consectetur adipiscing elit. Sed do eiusmod tempor incididunt."),
263
+ ],
264
+ },
265
+ {
266
+ type: "column",
267
+ attrs: { className: "p-3 gap-3 w-full box-border" },
268
+ content: [
269
+ blocks.paragraph("Ut enim ad minim veniam."),
270
+ blocks.paragraph("Quis nostrud exercitation ullamco laboris."),
271
+ ],
272
+ },
273
+ {
274
+ type: "column",
275
+ attrs: { className: "p-3 gap-3 w-full box-border" },
276
+ content: [
277
+ blocks.paragraph("Nisi ut aliquip ex ea commodo consequat."),
278
+ blocks.paragraph("Duis aute irure dolor in reprehenderit."),
279
+ ],
280
+ },
281
+ ],
282
+ },
283
+ ],
284
+ }),
285
+ };
286
+
287
+ const threeColumnsWithHeader: PresetTemplate = {
288
+ key: "tpl.threeColumnsWithHeader",
289
+ label: "Three Columns + Header",
290
+ description: "Header plus three columns",
291
+ icon: threeColumnsHeaderIcon,
292
+ build: () =>
293
+ slide.singleCol({
294
+ columnAttrs: { className: "w-full p-6 gap-4", horizontalAlign: "stretch" },
295
+ content: [
296
+ blocks.heading("Section heading", 2),
297
+ {
298
+ type: "row",
299
+ attrs: { layout: "1-1-1", className: "items-start w-full gap-4" },
300
+ content: [
301
+ {
302
+ type: "column",
303
+ attrs: { className: "p-3 gap-3 w-full box-border" },
304
+ content: [
305
+ blocks.heading("Column heading", 4),
306
+ blocks.paragraph("Lorem ipsum dolor sit amet."),
307
+ blocks.paragraph("Consectetur adipiscing elit. Sed do eiusmod tempor incididunt."),
308
+ ],
309
+ },
310
+ {
311
+ type: "column",
312
+ attrs: { className: "p-3 gap-3 w-full box-border" },
313
+ content: [
314
+ blocks.heading("Column heading", 4),
315
+ blocks.paragraph("Ut enim ad minim veniam."),
316
+ blocks.paragraph("Quis nostrud exercitation ullamco laboris."),
317
+ ],
318
+ },
319
+ {
320
+ type: "column",
321
+ attrs: { className: "p-3 gap-3 w-full box-border" },
322
+ content: [
323
+ blocks.heading("Column heading", 4),
324
+ blocks.paragraph("Nisi ut aliquip ex ea commodo consequat."),
325
+ blocks.paragraph("Duis aute irure dolor in reprehenderit."),
326
+ ],
327
+ },
328
+ ],
329
+ },
330
+ ],
331
+ }),
332
+ };
333
+
334
+ const fourColumnsWithHeader: PresetTemplate = {
335
+ key: "tpl.fourColumnsWithHeader",
336
+ label: "Four Columns + Header",
337
+ description: "Header plus four columns",
338
+ icon: fourColumnsHeaderIcon,
339
+ build: () =>
340
+ slide.singleCol({
341
+ columnAttrs: { className: "w-full p-6 gap-4", horizontalAlign: "stretch" },
342
+ content: [
343
+ blocks.heading("Section heading", 2),
344
+ {
345
+ type: "row",
346
+ attrs: { layout: "1-1-1-1", className: "items-start w-full gap-3" },
347
+ content: [
348
+ {
349
+ type: "column",
350
+ attrs: { className: "p-3 gap-3 w-full box-border" },
351
+ content: [
352
+ blocks.heading("Column heading", 4),
353
+ blocks.paragraph("Lorem ipsum dolor sit amet."),
354
+ blocks.paragraph("Consectetur adipiscing elit."),
355
+ ],
356
+ },
357
+ {
358
+ type: "column",
359
+ attrs: { className: "p-3 gap-3 w-full box-border" },
360
+ content: [
361
+ blocks.heading("Column heading", 4),
362
+ blocks.paragraph("Ut enim ad minim veniam."),
363
+ blocks.paragraph("Quis nostrud exercitation ullamco laboris."),
364
+ ],
365
+ },
366
+ {
367
+ type: "column",
368
+ attrs: { className: "p-3 gap-3 w-full box-border" },
369
+ content: [
370
+ blocks.heading("Column heading", 4),
371
+ blocks.paragraph("Nisi ut aliquip ex ea commodo consequat."),
372
+ blocks.paragraph("Duis aute irure dolor in reprehenderit."),
373
+ ],
374
+ },
375
+ {
376
+ type: "column",
377
+ attrs: { className: "p-3 gap-3 w-full box-border" },
378
+ content: [
379
+ blocks.heading("Column heading", 4),
380
+ blocks.paragraph("Excepteur sint occaecat cupidatat."),
381
+ blocks.paragraph("Sunt in culpa qui officia."),
382
+ ],
383
+ },
384
+ ],
385
+ },
386
+ ],
387
+ }),
388
+ };
389
+
390
+ const fullImage: PresetTemplate = {
391
+ key: "tpl.fullImage",
392
+ label: "Full Image",
393
+ description: "Edge-to-edge image filling the slide",
394
+ icon: fullImageIcon,
395
+ build: () =>
396
+ slide.singleCol({
397
+ rowAttrs: { className: "min-h-[720px]" },
398
+ columnAttrs: { className: "p-0 w-full h-full", horizontalAlign: "stretch" },
399
+ content: [
400
+ blocks.imageBlock({
401
+ src: "https://placehold.co/1920x1080/png",
402
+ layout: "cover",
403
+ fullBleed: true,
404
+ align: "center",
405
+ }),
406
+ ],
407
+ }),
408
+ };
409
+
410
+ const fourColumns: PresetTemplate = {
411
+ key: "tpl.fourColumns",
412
+ label: "Four Columns",
413
+ description: "Balanced four-column text",
414
+ icon: fourColumnsIcon,
415
+ build: () =>
416
+ slide.singleCol({
417
+ columnAttrs: { className: "w-full p-4 gap-4", horizontalAlign: "stretch" },
418
+ content: [
419
+ {
420
+ type: "row",
421
+ attrs: { layout: "1-1-1-1", className: "items-start w-full gap-3" },
422
+ content: Array.from({ length: 4 }).map(() => ({
423
+ type: "column",
424
+ attrs: { className: "p-2.5 gap-2 w-full box-border" },
425
+ content: [
426
+ blocks.paragraph("Lorem ipsum dolor sit amet."),
427
+ blocks.paragraph("Consectetur adipiscing elit."),
428
+ ],
429
+ })),
430
+ },
431
+ ],
432
+ }),
433
+ };
434
+
435
+ const titleWithBullets: PresetTemplate = {
436
+ key: "tpl.titleWithBullets",
437
+ label: "Title with Bullets",
438
+ description: "Header and a bullet list",
439
+ icon: titleBulletsIcon,
440
+ build: () =>
441
+ slide.singleCol({
442
+ columnAttrs: { className: "p-6 gap-4" },
443
+ content: [
444
+ blocks.heading("Lorem ipsum dolor sit amet", 2),
445
+ blocks.bulletList([
446
+ "Consectetur adipiscing elit.",
447
+ "Sed do eiusmod tempor incididunt.",
448
+ "Ut enim ad minim veniam.",
449
+ ]),
450
+ ],
451
+ }),
452
+ };
453
+
454
+ const titleBulletsAndImage: PresetTemplate = {
455
+ key: "tpl.titleBulletsAndImage",
456
+ label: "Title, Bullets & Image",
457
+ description: "Title with bullets and an image",
458
+ icon: titleBulletsImageIcon,
459
+ build: () =>
460
+ slide.twoCol({
461
+ rowAttrs: { className: "items-start w-full" },
462
+ leftColumnAttrs: { className: "p-6 gap-3 w-full" },
463
+ rightColumnAttrs: {
464
+ horizontalAlign: "center",
465
+ verticalAlign: "center",
466
+ className: "p-6 w-full",
467
+ },
468
+ left: [
469
+ blocks.heading("Lorem ipsum dolor sit amet", 2),
470
+ blocks.bulletList([
471
+ "Consectetur adipiscing elit.",
472
+ "Sed do eiusmod tempor incididunt.",
473
+ "Ut enim ad minim veniam.",
474
+ ]),
475
+ ],
476
+ right: [
477
+ blocks.imageBlock({
478
+ src: "https://placehold.co/480x360/png",
479
+ layout: "contain",
480
+ fullBleed: false,
481
+ }),
482
+ ],
483
+ }),
484
+ };
485
+
486
+ const accentLeft: PresetTemplate = {
487
+ key: "tpl.accentLeft",
488
+ label: "Accent left",
489
+ description: "Accent band with image on the left, text on the right",
490
+ icon: accentLeftIcon,
491
+ build: () =>
492
+ slide.twoCol({
493
+ rowAttrs: { layout: "1-2", className: "items-stretch w-full gap-0 min-h-[360px]" },
494
+ leftColumnAttrs: {
495
+ className: "bg-slate-100 p-0 w-full h-full",
496
+ horizontalAlign: "stretch",
497
+ verticalAlign: "top",
498
+ },
499
+ rightColumnAttrs: { className: "p-6 gap-3 w-full", verticalAlign: "center" },
500
+ left: [
501
+ blocks.imageBlock({
502
+ src: "https://placehold.co/320x240/png",
503
+ layout: "cover",
504
+ fullBleed: true,
505
+ align: "center",
506
+ }),
507
+ ],
508
+ right: [
509
+ blocks.heading("Accent left", 3),
510
+ blocks.paragraph("Short supporting copy goes here."),
511
+ blocks.paragraph("Add one more line if needed."),
512
+ ],
513
+ }),
514
+ };
515
+
516
+ const accentRight: PresetTemplate = {
517
+ key: "tpl.accentRight",
518
+ label: "Accent right",
519
+ description: "Accent band with image on the right, text on the left",
520
+ icon: accentRightIcon,
521
+ build: () =>
522
+ slide.twoCol({
523
+ rowAttrs: { layout: "2-1", className: "items-stretch w-full gap-0 min-h-[360px]" },
524
+ leftColumnAttrs: { className: "p-6 gap-3 w-full", verticalAlign: "center" },
525
+ rightColumnAttrs: {
526
+ className: "bg-slate-100 p-0 w-full h-full",
527
+ horizontalAlign: "stretch",
528
+ verticalAlign: "top",
529
+ },
530
+ left: [
531
+ blocks.heading("Accent right", 3),
532
+ blocks.paragraph("Short supporting copy goes here."),
533
+ blocks.paragraph("Add one more line if needed."),
534
+ ],
535
+ right: [
536
+ blocks.imageBlock({
537
+ src: "https://placehold.co/320x240/png",
538
+ layout: "cover",
539
+ fullBleed: true,
540
+ align: "center",
541
+ }),
542
+ ],
543
+ }),
544
+ };
545
+
546
+ const accentTop: PresetTemplate = {
547
+ key: "tpl.accentTop",
548
+ label: "Accent top",
549
+ description: "Accent band on top with image, text below",
550
+ icon: accentTopIcon,
551
+ build: () =>
552
+ ({
553
+ type: "slide",
554
+ attrs: { id: "slide-1", size: "16x9", className: "" },
555
+ content: [
556
+ {
557
+ type: "row",
558
+ attrs: { layout: "1", className: "w-full items-stretch h-[20vh] min-h-[140px]" },
559
+ content: [
560
+ {
561
+ type: "column",
562
+ attrs: { className: "bg-slate-100 p-0 w-full h-full box-border" },
563
+ content: [
564
+ blocks.imageBlock({
565
+ src: "https://placehold.co/1200x400/png",
566
+ layout: "cover",
567
+ fullBleed: true,
568
+ align: "center",
569
+ }),
570
+ ],
571
+ },
572
+ ],
573
+ },
574
+ {
575
+ type: "row",
576
+ attrs: { layout: "1", className: "w-full flex-1" },
577
+ content: [
578
+ {
579
+ type: "column",
580
+ attrs: { className: "p-6 gap-3 w-full box-border justify-end" },
581
+ content: [
582
+ blocks.heading("Accent top", 3),
583
+ blocks.paragraph("Short supporting copy goes here."),
584
+ blocks.paragraph("Add one more line if needed."),
585
+ ],
586
+ },
587
+ ],
588
+ },
589
+ ],
590
+ } as SlideNode),
591
+ };
592
+
593
+ const accentRightFit: PresetTemplate = {
594
+ key: "tpl.accentRightFit",
595
+ label: "Accent right (fit)",
596
+ description: "Text with a tighter image card on the right",
597
+ icon: accentRightFitIcon,
598
+ build: () =>
599
+ slide.twoCol({
600
+ rowAttrs: { layout: "2-1", className: "items-center w-full gap-4" },
601
+ leftColumnAttrs: { className: "p-6 gap-3 w-full", verticalAlign: "center" },
602
+ rightColumnAttrs: {
603
+ className: "p-6 w-full items-center",
604
+ verticalAlign: "center",
605
+ horizontalAlign: "center",
606
+ },
607
+ left: [
608
+ blocks.heading("Accent right (fit)", 3),
609
+ blocks.paragraph("Short supporting copy goes here."),
610
+ blocks.paragraph("Add one more line if needed."),
611
+ ],
612
+ right: [
613
+ {
614
+ type: "column",
615
+ attrs: { className: "bg-slate-100 p-4 gap-3 rounded-lg w-full items-center" },
616
+ content: [
617
+ blocks.imageBlock({
618
+ src: "https://placehold.co/240x200/png",
619
+ layout: "contain",
620
+ fullBleed: false,
621
+ align: "center",
622
+ }),
623
+ ],
624
+ },
625
+ ],
626
+ }),
627
+ };
628
+
629
+ const accentLeftFit: PresetTemplate = {
630
+ key: "tpl.accentLeftFit",
631
+ label: "Accent left (fit)",
632
+ description: "Compact image card on the left, text on the right",
633
+ icon: accentLeftFitIcon,
634
+ build: () =>
635
+ slide.twoCol({
636
+ rowAttrs: { layout: "1-2", className: "items-center w-full gap-4" },
637
+ leftColumnAttrs: {
638
+ className: "p-6 w-full items-center",
639
+ verticalAlign: "center",
640
+ horizontalAlign: "center",
641
+ },
642
+ rightColumnAttrs: { className: "p-6 gap-3 w-full", verticalAlign: "center" },
643
+ left: [
644
+ {
645
+ type: "column",
646
+ attrs: { className: "bg-slate-100 p-4 gap-3 rounded-lg w-full items-center" },
647
+ content: [
648
+ blocks.imageBlock({
649
+ src: "https://placehold.co/240x200/png",
650
+ layout: "contain",
651
+ fullBleed: false,
652
+ align: "center",
653
+ }),
654
+ ],
655
+ },
656
+ ],
657
+ right: [
658
+ blocks.heading("Accent left (fit)", 3),
659
+ blocks.paragraph("Short supporting copy goes here."),
660
+ blocks.paragraph("Add one more line if needed."),
661
+ ],
662
+ }),
663
+ };
664
+
665
+ const twoImageColumns: PresetTemplate = {
666
+ key: "tpl.twoImageColumns",
667
+ label: "2 image columns",
668
+ description: "Header with two image cards",
669
+ icon: twoImageColumnsIcon,
670
+ build: () =>
671
+ slide.singleCol({
672
+ columnAttrs: { className: "w-full p-6 gap-4", horizontalAlign: "stretch" },
673
+ content: [
674
+ blocks.heading("Images", 2),
675
+ {
676
+ type: "row",
677
+ attrs: { layout: "1-1", className: "items-start w-full gap-4" },
678
+ content: [
679
+ {
680
+ type: "column",
681
+ attrs: { className: "p-4 gap-3 w-full box-border" },
682
+ content: [
683
+ blocks.imageBlock({
684
+ src: "https://placehold.co/640x360/png",
685
+ layout: "contain",
686
+ fullBleed: false,
687
+ align: "center",
688
+ }),
689
+ blocks.heading("Image title", 4),
690
+ blocks.paragraph("Short supporting copy goes here."),
691
+ ],
692
+ },
693
+ {
694
+ type: "column",
695
+ attrs: { className: "p-4 gap-3 w-full box-border" },
696
+ content: [
697
+ blocks.imageBlock({
698
+ src: "https://placehold.co/640x360/png",
699
+ layout: "contain",
700
+ fullBleed: false,
701
+ align: "center",
702
+ }),
703
+ blocks.heading("Image title", 4),
704
+ blocks.paragraph("Short supporting copy goes here."),
705
+ ],
706
+ },
707
+ ],
708
+ },
709
+ ],
710
+ }),
711
+ };
712
+
713
+ const registry: Record<PresetKey, PresetTemplate> = {
714
+ "tpl.titleAndSubheader": titleAndSubheader,
715
+ "tpl.imageAndText": imageAndText,
716
+ "tpl.textAndImage": textAndImage,
717
+ "tpl.twoColumns": twoColumns,
718
+ "tpl.twoColumnsWithHeader": twoColumnsWithHeader,
719
+ "tpl.threeColumns": threeColumns,
720
+ "tpl.threeColumnsWithHeader": threeColumnsWithHeader,
721
+ "tpl.fourColumns": fourColumns,
722
+ "tpl.fourColumnsWithHeader": fourColumnsWithHeader,
723
+ "tpl.titleWithBullets": titleWithBullets,
724
+ "tpl.titleBulletsAndImage": titleBulletsAndImage,
725
+ "tpl.fullImage": fullImage,
726
+ "tpl.accentLeft": accentLeft,
727
+ "tpl.accentRight": accentRight,
728
+ "tpl.accentTop": accentTop,
729
+ "tpl.accentRightFit": accentRightFit,
730
+ "tpl.accentLeftFit": accentLeftFit,
731
+ "tpl.twoImageColumns": twoImageColumns,
732
+
733
+ };
734
+
735
+ export const listPresetTemplates = (): PresetTemplate[] => Object.values(registry);
736
+
737
+ export const buildPresetTemplate = (key: PresetKey): SlideNode => registry[key].build();
738
+
739
+ export type { PresetTemplate };