@contentrain/astro-kit 0.30.0 → 0.32.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.
Files changed (67) hide show
  1. package/README.md +25 -2
  2. package/catalog.json +3305 -83
  3. package/components/_shared/Section.astro +18 -3
  4. package/components/_shared/measured.ts +152 -0
  5. package/components/_shared/types.ts +40 -0
  6. package/components/band/Band.astro +132 -0
  7. package/components/band/fixtures.json +8 -0
  8. package/components/band/meta.json +323 -0
  9. package/components/card-grid/CardGrid.astro +7 -3
  10. package/components/card-grid/fixtures.json +2 -1
  11. package/components/card-grid/meta.json +111 -0
  12. package/components/contact-details/ContactDetails.astro +7 -2
  13. package/components/contact-details/meta.json +113 -1
  14. package/components/contact-form/ContactForm.astro +48 -12
  15. package/components/contact-form/fixtures.json +169 -9
  16. package/components/contact-form/meta.json +283 -15
  17. package/components/cta/Cta.astro +52 -12
  18. package/components/cta/fixtures.json +5 -1
  19. package/components/cta/meta.json +11 -2
  20. package/components/faq/Faq.astro +60 -17
  21. package/components/faq/fixtures.json +75 -0
  22. package/components/faq/meta.json +8 -2
  23. package/components/feature-list/FeatureList.astro +34 -6
  24. package/components/feature-list/fixtures.json +2 -1
  25. package/components/feature-list/meta.json +125 -1
  26. package/components/gallery/Gallery.astro +47 -13
  27. package/components/gallery/fixtures.json +275 -0
  28. package/components/gallery/meta.json +266 -14
  29. package/components/hero/Hero.astro +14 -8
  30. package/components/hero/fixtures.json +2 -1
  31. package/components/hero/meta.json +111 -0
  32. package/components/logo-cloud/LogoCloud.astro +85 -21
  33. package/components/logo-cloud/fixtures.json +239 -0
  34. package/components/logo-cloud/meta.json +145 -5
  35. package/components/newsletter/Newsletter.astro +5 -1
  36. package/components/newsletter/meta.json +113 -1
  37. package/components/post-card/PostCard.astro +4 -2
  38. package/components/post-card/meta.json +2 -1
  39. package/components/post-list/PostList.astro +114 -0
  40. package/components/post-list/fixtures.json +387 -0
  41. package/components/post-list/meta.json +308 -0
  42. package/components/pricing/Pricing.astro +128 -24
  43. package/components/pricing/fixtures.json +288 -4
  44. package/components/pricing/meta.json +188 -1
  45. package/components/split/Split.astro +76 -14
  46. package/components/split/fixtures.json +8 -1
  47. package/components/split/meta.json +226 -4
  48. package/components/stats/Stats.astro +42 -10
  49. package/components/stats/fixtures.json +173 -0
  50. package/components/stats/meta.json +153 -5
  51. package/components/steps/Steps.astro +36 -8
  52. package/components/steps/fixtures.json +217 -5
  53. package/components/steps/meta.json +157 -3
  54. package/components/tabs/Tabs.astro +5 -2
  55. package/components/tabs/meta.json +2 -1
  56. package/components/team/Team.astro +52 -8
  57. package/components/team/fixtures.json +217 -4
  58. package/components/team/meta.json +168 -3
  59. package/components/team/team.ts +9 -0
  60. package/components/testimonial/Testimonial.astro +71 -21
  61. package/components/testimonial/fixtures.json +73 -0
  62. package/components/testimonial/meta.json +167 -3
  63. package/mapping/classic.json +7 -1
  64. package/mapping/divi.json +21 -4
  65. package/mapping/elementor.json +33 -8
  66. package/mapping/gutenberg.json +20 -4
  67. package/package.json +2 -2
@@ -0,0 +1,114 @@
1
+ ---
2
+ // A list of posts as cards: a grid, stacked rows, a featured first post over a
3
+ // grid, or a compact title-and-date list. The posts are the site's own — fed
4
+ // by the Contentrain query SDK, never copied from a page — and the `show*`
5
+ // switches decide which parts of each card the design displays.
6
+ import { tv } from 'tailwind-variants'
7
+ import Section from '../_shared/Section.astro'
8
+ import { measuredGrid } from '../_shared/measured'
9
+ import type { MeasuredStyle } from '../_shared/types'
10
+ import PostCard from '../post-card/PostCard.astro'
11
+ import type { ImageInput, LinkInput } from '../_shared/types'
12
+
13
+ export interface PostItem {
14
+ title: string
15
+ href: string
16
+ excerpt?: string | undefined
17
+ date?: Date | string | undefined
18
+ image?: ImageInput | undefined
19
+ category?: LinkInput | undefined
20
+ author?: string | undefined
21
+ }
22
+
23
+ const list = tv({
24
+ slots: {
25
+ header: 'mb-10 flex max-w-2xl flex-col gap-3',
26
+ heading: 'text-3xl [font-weight:var(--font-weight-heading,700)] tracking-tight text-balance md:text-4xl',
27
+ intro: 'text-lg opacity-80',
28
+ items: 'grid gap-8',
29
+ more: 'mt-10',
30
+ },
31
+ variants: {
32
+ layout: {
33
+ grid: { items: 'sm:grid-cols-2' },
34
+ list: { items: 'gap-6' },
35
+ // The first post spans the whole row, image beside text; the others fill the grid under it.
36
+ featured: { items: 'sm:grid-cols-2 [&>li:first-child]:sm:col-span-2' },
37
+ compact: { items: 'gap-4' },
38
+ },
39
+ columns: { '2': {}, '3': {}, '4': {} },
40
+ },
41
+ compoundVariants: [
42
+ { layout: ['grid', 'featured'], columns: '3', class: { items: 'lg:grid-cols-3 [&>li:first-child]:lg:col-span-3' } },
43
+ { layout: ['grid', 'featured'], columns: '4', class: { items: 'md:grid-cols-2 lg:grid-cols-4 [&>li:first-child]:lg:col-span-4' } },
44
+ ],
45
+ defaultVariants: { layout: 'grid', columns: '3' },
46
+ })
47
+
48
+ interface Props {
49
+ heading?: string | undefined
50
+ intro?: string | undefined
51
+ posts: PostItem[]
52
+ layout?: 'grid' | 'list' | 'featured' | 'compact' | undefined
53
+ /** Cards per row on wide screens (grid and featured). */
54
+ columns?: '2' | '3' | '4' | undefined
55
+ /** Which parts of a card the design shows. */
56
+ showImage?: boolean | undefined
57
+ showExcerpt?: boolean | undefined
58
+ showAuthor?: boolean | undefined
59
+ showCategory?: boolean | undefined
60
+ excerptLines?: 2 | 3 | 4 | undefined
61
+ /** BCP 47 locale the dates are written in. */
62
+ locale?: string | undefined
63
+ /** Card surface: none, or each post its own card. */
64
+ surface?: 'plain' | 'card' | undefined
65
+ /** Where the full archive lives; with `moreLabel` a link follows the list. */
66
+ moreHref?: string | undefined
67
+ moreLabel?: string | undefined
68
+ tone?: 'default' | 'muted' | 'inverse' | 'accent' | undefined
69
+ /** The source section's measured style (`MeasuredStyle`): frame, padding, fill, background image, columns per width, gap. Absent, the site's tokens; present, it wins over tone and columns. */
70
+ measured?: MeasuredStyle | undefined
71
+ id?: string | undefined
72
+ }
73
+
74
+ const { heading, intro, posts, layout = 'grid', columns, showImage = true, showExcerpt = true, showAuthor = true, showCategory = true, excerptLines, locale, surface, moreHref, moreLabel, tone, measured, id = 'posts' } = Astro.props
75
+ const s = list({ layout, columns })
76
+ const headingId = heading ? `${id}-title` : undefined
77
+ // Cards sit one heading level under the section's; with no section heading they are the page's h2s.
78
+ const headingLevel = heading ? 3 : 2
79
+ const sizes = layout === 'list' || layout === 'compact' ? '256px' : columns === '4' ? '(min-width: 1024px) 25vw, 50vw' : columns === '2' ? '(min-width: 640px) 50vw, 100vw' : '(min-width: 1024px) 33vw, (min-width: 640px) 50vw, 100vw'
80
+ // A featured first post is read as a horizontal card; the rest take the grid's vertical one.
81
+ const cardLayout = (i: number) => layout === 'compact' ? 'minimal' : layout === 'list' || (layout === 'featured' && i === 0) ? 'horizontal' : 'vertical'
82
+ ---
83
+ {posts.length > 0 && (
84
+ <Section measured={measured} tone={tone} id={id} aria-labelledby={headingId}>
85
+ {(heading || intro) && (
86
+ <header class={s.header()}>
87
+ {heading && <h2 id={headingId} class={s.heading()}>{heading}</h2>}
88
+ {intro && <p class={s.intro()} data-kit-text>{intro}</p>}
89
+ </header>
90
+ )}
91
+ <ul class={s.items({ class: layout === 'grid' || layout === 'featured' ? measuredGrid(measured) : undefined })}>
92
+ {posts.map((post, i) => (
93
+ <li>
94
+ <PostCard
95
+ title={post.title}
96
+ href={post.href}
97
+ excerpt={showExcerpt && layout !== 'compact' ? post.excerpt : undefined}
98
+ date={post.date}
99
+ locale={locale}
100
+ image={showImage && layout !== 'compact' ? post.image : undefined}
101
+ category={showCategory && layout !== 'compact' ? post.category : undefined}
102
+ author={showAuthor && layout !== 'compact' ? post.author : undefined}
103
+ headingLevel={headingLevel}
104
+ layout={cardLayout(i)}
105
+ surface={surface}
106
+ excerptLines={excerptLines}
107
+ sizes={sizes}
108
+ />
109
+ </li>
110
+ ))}
111
+ </ul>
112
+ {moreHref && moreLabel && <p class={s.more()}><a href={moreHref} class="font-medium text-accent-text underline underline-offset-4">{moreLabel}</a></p>}
113
+ </Section>
114
+ )}
@@ -0,0 +1,387 @@
1
+ [
2
+ {
3
+ "name": "grid-3",
4
+ "props": {
5
+ "id": "posts",
6
+ "heading": "Latest posts",
7
+ "posts": [
8
+ {
9
+ "title": "What a careful migration keeps",
10
+ "href": "/blog/post-1/",
11
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
12
+ "date": "2026-09-21T09:00:00Z",
13
+ "category": {
14
+ "label": "Guides",
15
+ "href": "/category/guides/"
16
+ },
17
+ "author": "Mira Kovač",
18
+ "image": {
19
+ "src": "/kit-fixtures/photo-1.svg",
20
+ "alt": "Photo 1",
21
+ "width": 1200,
22
+ "height": 800
23
+ }
24
+ },
25
+ {
26
+ "title": "Designing for a hundred pages",
27
+ "href": "/blog/post-2/",
28
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
29
+ "date": "2026-09-22T09:00:00Z",
30
+ "category": {
31
+ "label": "Guides",
32
+ "href": "/category/guides/"
33
+ },
34
+ "author": "Mira Kovač",
35
+ "image": {
36
+ "src": "/kit-fixtures/photo-2.svg",
37
+ "alt": "Photo 2",
38
+ "width": 1200,
39
+ "height": 800
40
+ }
41
+ },
42
+ {
43
+ "title": "Redirects, one by one",
44
+ "href": "/blog/post-3/",
45
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
46
+ "date": "2026-09-23T09:00:00Z",
47
+ "category": {
48
+ "label": "Guides",
49
+ "href": "/category/guides/"
50
+ },
51
+ "author": "Mira Kovač",
52
+ "image": {
53
+ "src": "/kit-fixtures/photo-3.svg",
54
+ "alt": "Photo 3",
55
+ "width": 1200,
56
+ "height": 800
57
+ }
58
+ }
59
+ ]
60
+ }
61
+ },
62
+ {
63
+ "name": "list",
64
+ "props": {
65
+ "layout": "list",
66
+ "posts": [
67
+ {
68
+ "title": "What a careful migration keeps",
69
+ "href": "/blog/post-1/",
70
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
71
+ "date": "2026-09-21T09:00:00Z",
72
+ "category": {
73
+ "label": "Guides",
74
+ "href": "/category/guides/"
75
+ },
76
+ "author": "Mira Kovač",
77
+ "image": {
78
+ "src": "/kit-fixtures/photo-1.svg",
79
+ "alt": "Photo 1",
80
+ "width": 1200,
81
+ "height": 800
82
+ }
83
+ },
84
+ {
85
+ "title": "Designing for a hundred pages",
86
+ "href": "/blog/post-2/",
87
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
88
+ "date": "2026-09-22T09:00:00Z",
89
+ "category": {
90
+ "label": "Guides",
91
+ "href": "/category/guides/"
92
+ },
93
+ "author": "Mira Kovač",
94
+ "image": {
95
+ "src": "/kit-fixtures/photo-2.svg",
96
+ "alt": "Photo 2",
97
+ "width": 1200,
98
+ "height": 800
99
+ }
100
+ },
101
+ {
102
+ "title": "Redirects, one by one",
103
+ "href": "/blog/post-3/",
104
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
105
+ "date": "2026-09-23T09:00:00Z",
106
+ "category": {
107
+ "label": "Guides",
108
+ "href": "/category/guides/"
109
+ },
110
+ "author": "Mira Kovač",
111
+ "image": {
112
+ "src": "/kit-fixtures/photo-3.svg",
113
+ "alt": "Photo 3",
114
+ "width": 1200,
115
+ "height": 800
116
+ }
117
+ }
118
+ ],
119
+ "excerptLines": 2
120
+ }
121
+ },
122
+ {
123
+ "name": "featured-4",
124
+ "props": {
125
+ "layout": "featured",
126
+ "columns": "4",
127
+ "heading": "Journal",
128
+ "intro": "Notes from the studio.",
129
+ "posts": [
130
+ {
131
+ "title": "What a careful migration keeps",
132
+ "href": "/blog/post-1/",
133
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
134
+ "date": "2026-09-21T09:00:00Z",
135
+ "category": {
136
+ "label": "Guides",
137
+ "href": "/category/guides/"
138
+ },
139
+ "author": "Mira Kovač",
140
+ "image": {
141
+ "src": "/kit-fixtures/photo-1.svg",
142
+ "alt": "Photo 1",
143
+ "width": 1200,
144
+ "height": 800
145
+ }
146
+ },
147
+ {
148
+ "title": "Designing for a hundred pages",
149
+ "href": "/blog/post-2/",
150
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
151
+ "date": "2026-09-22T09:00:00Z",
152
+ "category": {
153
+ "label": "Guides",
154
+ "href": "/category/guides/"
155
+ },
156
+ "author": "Mira Kovač",
157
+ "image": {
158
+ "src": "/kit-fixtures/photo-2.svg",
159
+ "alt": "Photo 2",
160
+ "width": 1200,
161
+ "height": 800
162
+ }
163
+ },
164
+ {
165
+ "title": "Redirects, one by one",
166
+ "href": "/blog/post-3/",
167
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
168
+ "date": "2026-09-23T09:00:00Z",
169
+ "category": {
170
+ "label": "Guides",
171
+ "href": "/category/guides/"
172
+ },
173
+ "author": "Mira Kovač",
174
+ "image": {
175
+ "src": "/kit-fixtures/photo-3.svg",
176
+ "alt": "Photo 3",
177
+ "width": 1200,
178
+ "height": 800
179
+ }
180
+ },
181
+ {
182
+ "title": "A very long title that keeps going well past one line to prove the card wraps it without clipping",
183
+ "href": "/blog/post-4/",
184
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
185
+ "date": "2026-09-24T09:00:00Z",
186
+ "category": {
187
+ "label": "Guides",
188
+ "href": "/category/guides/"
189
+ },
190
+ "author": "Mira Kovač",
191
+ "image": {
192
+ "src": "/kit-fixtures/photo-4.svg",
193
+ "alt": "Photo 4",
194
+ "width": 1200,
195
+ "height": 800
196
+ }
197
+ }
198
+ ]
199
+ }
200
+ },
201
+ {
202
+ "name": "compact",
203
+ "props": {
204
+ "layout": "compact",
205
+ "heading": "Recent",
206
+ "posts": [
207
+ {
208
+ "title": "What a careful migration keeps",
209
+ "href": "/blog/post-1/",
210
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
211
+ "date": "2026-09-21T09:00:00Z",
212
+ "category": {
213
+ "label": "Guides",
214
+ "href": "/category/guides/"
215
+ },
216
+ "author": "Mira Kovač",
217
+ "image": {
218
+ "src": "/kit-fixtures/photo-1.svg",
219
+ "alt": "Photo 1",
220
+ "width": 1200,
221
+ "height": 800
222
+ }
223
+ },
224
+ {
225
+ "title": "Designing for a hundred pages",
226
+ "href": "/blog/post-2/",
227
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
228
+ "date": "2026-09-22T09:00:00Z",
229
+ "category": {
230
+ "label": "Guides",
231
+ "href": "/category/guides/"
232
+ },
233
+ "author": "Mira Kovač",
234
+ "image": {
235
+ "src": "/kit-fixtures/photo-2.svg",
236
+ "alt": "Photo 2",
237
+ "width": 1200,
238
+ "height": 800
239
+ }
240
+ },
241
+ {
242
+ "title": "Redirects, one by one",
243
+ "href": "/blog/post-3/",
244
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
245
+ "date": "2026-09-23T09:00:00Z",
246
+ "category": {
247
+ "label": "Guides",
248
+ "href": "/category/guides/"
249
+ },
250
+ "author": "Mira Kovač",
251
+ "image": {
252
+ "src": "/kit-fixtures/photo-3.svg",
253
+ "alt": "Photo 3",
254
+ "width": 1200,
255
+ "height": 800
256
+ }
257
+ },
258
+ {
259
+ "title": "A very long title that keeps going well past one line to prove the card wraps it without clipping",
260
+ "href": "/blog/post-4/",
261
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
262
+ "date": "2026-09-24T09:00:00Z",
263
+ "category": {
264
+ "label": "Guides",
265
+ "href": "/category/guides/"
266
+ },
267
+ "author": "Mira Kovač",
268
+ "image": {
269
+ "src": "/kit-fixtures/photo-4.svg",
270
+ "alt": "Photo 4",
271
+ "width": 1200,
272
+ "height": 800
273
+ }
274
+ }
275
+ ],
276
+ "moreHref": "/blog/",
277
+ "moreLabel": "All posts"
278
+ }
279
+ },
280
+ {
281
+ "name": "grid-2-no-parts",
282
+ "props": {
283
+ "columns": "2",
284
+ "showImage": false,
285
+ "showAuthor": false,
286
+ "showCategory": false,
287
+ "posts": [
288
+ {
289
+ "title": "What a careful migration keeps",
290
+ "href": "/blog/post-1/",
291
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
292
+ "date": "2026-09-21T09:00:00Z",
293
+ "category": {
294
+ "label": "Guides",
295
+ "href": "/category/guides/"
296
+ },
297
+ "author": "Mira Kovač",
298
+ "image": {
299
+ "src": "/kit-fixtures/photo-1.svg",
300
+ "alt": "Photo 1",
301
+ "width": 1200,
302
+ "height": 800
303
+ }
304
+ },
305
+ {
306
+ "title": "Designing for a hundred pages",
307
+ "href": "/blog/post-2/",
308
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
309
+ "date": "2026-09-22T09:00:00Z",
310
+ "category": {
311
+ "label": "Guides",
312
+ "href": "/category/guides/"
313
+ },
314
+ "author": "Mira Kovač",
315
+ "image": {
316
+ "src": "/kit-fixtures/photo-2.svg",
317
+ "alt": "Photo 2",
318
+ "width": 1200,
319
+ "height": 800
320
+ }
321
+ }
322
+ ]
323
+ }
324
+ },
325
+ {
326
+ "name": "missing-image-excerpt",
327
+ "props": {
328
+ "surface": "card",
329
+ "posts": [
330
+ {
331
+ "title": "What a careful migration keeps",
332
+ "href": "/blog/post-1/",
333
+ "date": "2026-09-21T09:00:00Z",
334
+ "category": {
335
+ "label": "Guides",
336
+ "href": "/category/guides/"
337
+ },
338
+ "author": "Mira Kovač"
339
+ },
340
+ {
341
+ "title": "Designing for a hundred pages",
342
+ "href": "/blog/post-2/",
343
+ "date": "2026-09-22T09:00:00Z",
344
+ "category": {
345
+ "label": "Guides",
346
+ "href": "/category/guides/"
347
+ },
348
+ "author": "Mira Kovač"
349
+ },
350
+ {
351
+ "title": "Redirects, one by one",
352
+ "href": "/blog/post-3/",
353
+ "date": "2026-09-23T09:00:00Z",
354
+ "category": {
355
+ "label": "Guides",
356
+ "href": "/category/guides/"
357
+ },
358
+ "author": "Mira Kovač"
359
+ }
360
+ ]
361
+ }
362
+ },
363
+ {
364
+ "name": "single-post",
365
+ "props": {
366
+ "posts": [
367
+ {
368
+ "title": "What a careful migration keeps",
369
+ "href": "/blog/post-1/",
370
+ "excerpt": "What a careful migration keeps: addresses, formatting and rankings, block by block.",
371
+ "date": "2026-09-21T09:00:00Z",
372
+ "category": {
373
+ "label": "Guides",
374
+ "href": "/category/guides/"
375
+ },
376
+ "author": "Mira Kovač",
377
+ "image": {
378
+ "src": "/kit-fixtures/photo-1.svg",
379
+ "alt": "Photo 1",
380
+ "width": 1200,
381
+ "height": 800
382
+ }
383
+ }
384
+ ]
385
+ }
386
+ }
387
+ ]