@contentrain/astro-kit 0.18.0 → 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/catalog.json +39 -2
- package/components/_shared/Section.astro +3 -1
- package/components/contact-form/ContactForm.astro +12 -4
- package/components/contact-form/fixtures.json +1 -0
- package/components/contact-form/meta.json +2 -1
- package/components/cta/Cta.astro +3 -2
- package/components/cta/fixtures.json +2 -1
- package/components/cta/meta.json +1 -1
- package/components/footer/Footer.astro +23 -4
- package/components/footer/fixtures.json +3 -1
- package/components/footer/meta.json +28 -0
- package/mapping/gutenberg.json +11 -2
- package/package.json +2 -2
package/catalog.json
CHANGED
|
@@ -520,7 +520,15 @@
|
|
|
520
520
|
"stacked"
|
|
521
521
|
],
|
|
522
522
|
"default": "split",
|
|
523
|
-
"description": "split: details beside the form on wide screens. stacked: one
|
|
523
|
+
"description": "split: details beside the form on wide screens. stacked: one column (see align)."
|
|
524
|
+
},
|
|
525
|
+
"align": {
|
|
526
|
+
"options": [
|
|
527
|
+
"center",
|
|
528
|
+
"start"
|
|
529
|
+
],
|
|
530
|
+
"default": "center",
|
|
531
|
+
"description": "Stacked only, and the details alone before a Studio form. center: one centred column at a reading width. start: the section's whole column from the start edge, as a page builder's container whose text sets no alignment."
|
|
524
532
|
},
|
|
525
533
|
"tone": {
|
|
526
534
|
"options": [
|
|
@@ -653,10 +661,11 @@
|
|
|
653
661
|
"muted",
|
|
654
662
|
"inverse",
|
|
655
663
|
"accent",
|
|
664
|
+
"brand",
|
|
656
665
|
"none"
|
|
657
666
|
],
|
|
658
667
|
"default": "accent",
|
|
659
|
-
"description": "Background. On accent, primary buttons are drawn in the secondary style so they stay visible. none: no fill of its own; the page background shows through (a source colour the palette does not have)."
|
|
668
|
+
"description": "Background. On accent, primary buttons are drawn in the secondary style so they stay visible. brand: the site's brand colour role (`--color-brand`, the builder's own colour on a band) with its ink; buttons keep their style. none: no fill of its own; the page background shows through (a source colour the palette does not have)."
|
|
660
669
|
},
|
|
661
670
|
"actionsAlign": {
|
|
662
671
|
"options": [
|
|
@@ -1145,6 +1154,22 @@
|
|
|
1145
1154
|
],
|
|
1146
1155
|
"default": "start",
|
|
1147
1156
|
"description": "start: brand and links to the sides (left-aligned on phones). center: everything centred in one column, as themes with a centred footer print it."
|
|
1157
|
+
},
|
|
1158
|
+
"pack": {
|
|
1159
|
+
"options": [
|
|
1160
|
+
"spread",
|
|
1161
|
+
"end"
|
|
1162
|
+
],
|
|
1163
|
+
"default": "spread",
|
|
1164
|
+
"description": "columns layout only. spread: the link columns share the footer's width after the brand column. end: they are packed at the end edge at their own width, as a theme whose footer is the brand left and its menus on the right."
|
|
1165
|
+
},
|
|
1166
|
+
"narrow": {
|
|
1167
|
+
"options": [
|
|
1168
|
+
"stack",
|
|
1169
|
+
"row"
|
|
1170
|
+
],
|
|
1171
|
+
"default": "stack",
|
|
1172
|
+
"description": "Packed columns only, below the md breakpoint. stack: one column. row: still side by side from the start edge, under the brand."
|
|
1148
1173
|
}
|
|
1149
1174
|
},
|
|
1150
1175
|
"props": {
|
|
@@ -1241,6 +1266,18 @@
|
|
|
1241
1266
|
"navLabel": {
|
|
1242
1267
|
"type": "string",
|
|
1243
1268
|
"description": "Accessible name of the footer navigation (ui-strings nav.footer)."
|
|
1269
|
+
},
|
|
1270
|
+
"packGap": {
|
|
1271
|
+
"type": "string",
|
|
1272
|
+
"description": "Packed columns only: the space between columns, a CSS length such as 98px."
|
|
1273
|
+
},
|
|
1274
|
+
"packGapNarrow": {
|
|
1275
|
+
"type": "string",
|
|
1276
|
+
"description": "Packed columns in a row only: the space between them below the md breakpoint, a CSS length."
|
|
1277
|
+
},
|
|
1278
|
+
"linkSize": {
|
|
1279
|
+
"type": "string",
|
|
1280
|
+
"description": "Font size of the footer's links, a CSS length such as 17.88px; absent, the footer's own."
|
|
1244
1281
|
}
|
|
1245
1282
|
},
|
|
1246
1283
|
"slots": {},
|
|
@@ -12,6 +12,8 @@ const section = tv({
|
|
|
12
12
|
muted: 'bg-surface-muted text-ink',
|
|
13
13
|
inverse: 'bg-ink text-surface',
|
|
14
14
|
accent: 'bg-accent text-accent-ink',
|
|
15
|
+
// The site's brand colour where it is not the accent (a band the source paints in the builder's own colour).
|
|
16
|
+
brand: 'bg-brand text-brand-ink',
|
|
15
17
|
// No fill of its own: the page's background and text colour show through.
|
|
16
18
|
none: '',
|
|
17
19
|
},
|
|
@@ -28,7 +30,7 @@ const section = tv({
|
|
|
28
30
|
export type Tone = 'default' | 'muted' | 'inverse' | 'accent'
|
|
29
31
|
|
|
30
32
|
interface Props {
|
|
31
|
-
tone?: Tone | 'none' | undefined
|
|
33
|
+
tone?: Tone | 'brand' | 'none' | undefined
|
|
32
34
|
spacing?: 'none' | 'sm' | 'md' | 'lg' | undefined
|
|
33
35
|
/** `page` is the full frame, `prose` the reading column, `none` for full-bleed content. */
|
|
34
36
|
width?: 'page' | 'prose' | 'none' | undefined
|
|
@@ -37,12 +37,18 @@ const contact = tv({
|
|
|
37
37
|
variants: {
|
|
38
38
|
layout: {
|
|
39
39
|
split: { grid: 'md:grid-cols-[2fr_3fr] md:items-start' },
|
|
40
|
-
stacked: {
|
|
40
|
+
stacked: {},
|
|
41
41
|
},
|
|
42
|
+
// The stacked column: centred in a reading width, or the section's whole column from its start edge (a page
|
|
43
|
+
// builder's container whose text has no alignment of its own sits left, full width).
|
|
44
|
+
align: { center: {}, start: {} },
|
|
42
45
|
// accent/accent-ink is only ~5:1 — dimming text on it drops body copy under 4.5:1 (WCAG 1.4.3), so accent keeps it at full strength.
|
|
43
46
|
tone: { default: { form: 'border border-line bg-surface p-6 md:p-8' }, muted: { form: 'bg-surface p-6 text-ink md:p-8' }, inverse: { form: 'bg-surface p-6 text-ink md:p-8' }, accent: { form: 'bg-surface p-6 text-ink md:p-8', intro: 'opacity-100', term: 'opacity-100' } },
|
|
44
47
|
},
|
|
45
|
-
|
|
48
|
+
compoundVariants: [
|
|
49
|
+
{ layout: 'stacked', align: 'center', class: { grid: 'mx-auto max-w-2xl' } },
|
|
50
|
+
],
|
|
51
|
+
defaultVariants: { layout: 'split', tone: 'default', align: 'center' },
|
|
46
52
|
})
|
|
47
53
|
|
|
48
54
|
interface Props {
|
|
@@ -54,14 +60,16 @@ interface Props {
|
|
|
54
60
|
formHeading?: string | undefined
|
|
55
61
|
details?: ContactDetail[] | undefined
|
|
56
62
|
layout?: 'split' | 'stacked' | undefined
|
|
63
|
+
/** Stacked only (and the details alone, before a Studio form): a centred column, or the whole column from the start edge. */
|
|
64
|
+
align?: 'center' | 'start' | undefined
|
|
57
65
|
tone?: 'default' | 'muted' | 'inverse' | 'accent' | undefined
|
|
58
66
|
id?: string | undefined
|
|
59
67
|
}
|
|
60
68
|
|
|
61
|
-
const { model, heading, intro, formHeading, details = [], layout, tone, id = 'contact' } = Astro.props
|
|
69
|
+
const { model, heading, intro, formHeading, details = [], layout, align, tone, id = 'contact' } = Astro.props
|
|
62
70
|
// Nothing to render (Studio not bound yet): a split would leave an empty column — the details stand alone.
|
|
63
71
|
const formShown = formHome(model) !== null
|
|
64
|
-
const s = contact({ layout: formShown ? layout : 'stacked', tone })
|
|
72
|
+
const s = contact({ layout: formShown ? layout : 'stacked', align, tone })
|
|
65
73
|
const headingId = heading ? `${id}-title` : undefined
|
|
66
74
|
// A description list needs a term for every detail; an icon list carried from the source has values only.
|
|
67
75
|
const labelled = details.every(detail => detail.label)
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
{ "name": "stacked-muted", "props": { "model": "contact-submissions", "heading": "Write to us", "layout": "stacked", "tone": "muted", "id": "write" } },
|
|
16
|
+
{ "name": "stacked-start", "props": { "model": "contact-submissions", "intro": "Tell us what you make and when you want to launch.", "details": [{ "value": "Studio 4, Harbour Lane" }], "layout": "stacked", "align": "start", "id": "start" } },
|
|
16
17
|
{ "name": "split-inverse", "props": { "model": "contact-submissions", "heading": "Press", "tone": "inverse", "id": "press", "details": [{ "label": "Press office", "value": "press@northwind.example", "href": "mailto:press@northwind.example" }] } },
|
|
17
18
|
{ "name": "stacked-accent", "props": { "model": "newsletter-requests", "heading": "Request a print copy", "layout": "stacked", "tone": "accent", "id": "print" } },
|
|
18
19
|
{ "name": "form-heading", "props": { "model": "contact-submissions", "heading": "Contact", "intro": "Tell us where you are and what you need.", "formHeading": "Tell us about your project", "details": [{ "label": "Address", "value": "12 Harbour Street, Leith" }] } }
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
"uses": [],
|
|
7
7
|
"shared": ["Section.astro"],
|
|
8
8
|
"variants": {
|
|
9
|
-
"layout": { "options": ["split", "stacked"], "default": "split", "description": "split: details beside the form on wide screens. stacked: one
|
|
9
|
+
"layout": { "options": ["split", "stacked"], "default": "split", "description": "split: details beside the form on wide screens. stacked: one column (see align)." },
|
|
10
|
+
"align": { "options": ["center", "start"], "default": "center", "description": "Stacked only, and the details alone before a Studio form. center: one centred column at a reading width. start: the section's whole column from the start edge, as a page builder's container whose text sets no alignment." },
|
|
10
11
|
"tone": { "options": ["default", "muted", "inverse", "accent"], "default": "default", "description": "Section background; the form always sits on a surface card." }
|
|
11
12
|
},
|
|
12
13
|
"props": {
|
package/components/cta/Cta.astro
CHANGED
|
@@ -27,7 +27,7 @@ const cta = tv({
|
|
|
27
27
|
},
|
|
28
28
|
// accent/accent-ink is only ~5:1 — dimming text on it drops body copy under 4.5:1 (WCAG 1.4.3), so accent keeps it at full strength.
|
|
29
29
|
// none: no fill of its own — the page background and text colour show through.
|
|
30
|
-
tone: { default: {}, muted: {}, inverse: {}, accent: { body: 'opacity-100' }, none: {} },
|
|
30
|
+
tone: { default: {}, muted: {}, inverse: {}, accent: { body: 'opacity-100' }, brand: { body: 'opacity-100' }, none: {} },
|
|
31
31
|
// The buttons' own alignment: `start` keeps them at the start edge under centred text (a WordPress buttons block
|
|
32
32
|
// with no justification sits left in a group whose heading and paragraph are centred). The row is the text's
|
|
33
33
|
// column, as WordPress's content width is, not the whole section. Only centred needs it: inline and stacked
|
|
@@ -40,6 +40,7 @@ const cta = tv({
|
|
|
40
40
|
{ frame: 'card', tone: 'muted', class: { box: 'border-transparent bg-surface-muted text-ink' } },
|
|
41
41
|
{ frame: 'card', tone: 'inverse', class: { box: 'border-transparent bg-ink text-surface' } },
|
|
42
42
|
{ frame: 'card', tone: 'accent', class: { box: 'border-transparent bg-accent text-accent-ink' } },
|
|
43
|
+
{ frame: 'card', tone: 'brand', class: { box: 'border-transparent bg-brand text-brand-ink' } },
|
|
43
44
|
{ layout: 'centered', actionsAlign: 'start', class: { actions: 'w-full max-w-2xl justify-start' } },
|
|
44
45
|
],
|
|
45
46
|
defaultVariants: { layout: 'inline', frame: 'full', tone: 'accent', actionsAlign: 'inherit' },
|
|
@@ -51,7 +52,7 @@ interface Props {
|
|
|
51
52
|
actions: ActionInput[]
|
|
52
53
|
layout?: 'inline' | 'centered' | 'stacked' | undefined
|
|
53
54
|
frame?: 'full' | 'card' | undefined
|
|
54
|
-
tone?: 'default' | 'muted' | 'inverse' | 'accent' | 'none' | undefined
|
|
55
|
+
tone?: 'default' | 'muted' | 'inverse' | 'accent' | 'brand' | 'none' | undefined
|
|
55
56
|
/** The buttons' alignment: as the layout sets it, or at the start edge under centred text (layout centered). */
|
|
56
57
|
actionsAlign?: 'inherit' | 'start' | undefined
|
|
57
58
|
id?: string | undefined
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
{ "name": "card-default", "props": { "heading": "Write for the journal", "body": "We publish reader essays every season.", "frame": "card", "tone": "default", "actions": [{ "label": "Pitch an essay", "href": "/pitch/" }] } },
|
|
5
5
|
{ "name": "card-muted", "props": { "heading": "Support independent travel writing", "frame": "card", "tone": "muted", "layout": "centered", "actions": [{ "label": "Become a member", "href": "/members/" }] } },
|
|
6
6
|
{ "name": "stacked-none", "props": { "heading": "Ready when you are", "body": "Tell us where you want to go and we will send a first plan within a week.", "layout": "stacked", "tone": "none", "actions": [{ "label": "Start planning", "href": "/contact/" }] } },
|
|
7
|
-
{ "name": "centered-actions-start", "props": { "heading": "See what is on this week", "body": "New films every Thursday, and a late show on Saturdays.", "layout": "centered", "tone": "inverse", "actionsAlign": "start", "actions": [{ "label": "Programme", "href": "/programme/" }] } }
|
|
7
|
+
{ "name": "centered-actions-start", "props": { "heading": "See what is on this week", "body": "New films every Thursday, and a late show on Saturdays.", "layout": "centered", "tone": "inverse", "actionsAlign": "start", "actions": [{ "label": "Programme", "href": "/programme/" }] } },
|
|
8
|
+
{ "name": "centered-brand", "props": { "heading": "Ready when you are", "body": "Two launch slots left this quarter.", "layout": "centered", "tone": "brand", "actions": [{ "label": "Book a launch call", "href": "/contact/" }] } }
|
|
8
9
|
]
|
package/components/cta/meta.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"variants": {
|
|
9
9
|
"layout": { "options": ["inline", "centered", "stacked"], "default": "inline", "description": "inline: text left, buttons right on wide screens. centered: everything centred. stacked: heading, text and buttons in one column at the start edge on every width." },
|
|
10
10
|
"frame": { "options": ["full", "card"], "default": "full", "description": "full: the tone fills the section. card: a rounded box in a plain section carries the tone." },
|
|
11
|
-
"tone": { "options": ["default", "muted", "inverse", "accent", "none"], "default": "accent", "description": "Background. On accent, primary buttons are drawn in the secondary style so they stay visible. none: no fill of its own; the page background shows through (a source colour the palette does not have)." },
|
|
11
|
+
"tone": { "options": ["default", "muted", "inverse", "accent", "brand", "none"], "default": "accent", "description": "Background. On accent, primary buttons are drawn in the secondary style so they stay visible. brand: the site's brand colour role (`--color-brand`, the builder's own colour on a band) with its ink; buttons keep their style. none: no fill of its own; the page background shows through (a source colour the palette does not have)." },
|
|
12
12
|
"actionsAlign": { "options": ["inherit", "start"], "default": "inherit", "description": "The buttons' alignment. inherit: as the layout sets it. start: at the start edge under centred heading and text (layout centered; a WordPress buttons block with no justification in a centred group). inline and stacked ignore it." }
|
|
13
13
|
},
|
|
14
14
|
"props": {
|
|
@@ -22,11 +22,18 @@ const footer = tv({
|
|
|
22
22
|
inverse: { root: 'bg-ink text-surface' },
|
|
23
23
|
},
|
|
24
24
|
align: { start: {}, center: { inner: 'items-center justify-items-center text-center md:items-center [&_ul]:justify-center' } },
|
|
25
|
+
// The `columns` layout's link columns: spread from the brand column over the footer's width, or packed at the end
|
|
26
|
+
// edge at their own width (a theme whose footer is the brand left and its menus on the right).
|
|
27
|
+
pack: { spread: {}, end: {} },
|
|
28
|
+
// Packed columns below `md`: stacked, or still side by side from the start edge under the brand.
|
|
29
|
+
narrow: { stack: {}, row: { inner: 'grid-cols-[repeat(var(--footer-columns),auto)] justify-start gap-x-[var(--footer-gap-narrow,1.5rem)]' } },
|
|
25
30
|
},
|
|
26
31
|
compoundVariants: [
|
|
27
32
|
{ layout: 'simple', align: 'center', class: { inner: 'md:flex-col md:justify-center' } },
|
|
33
|
+
{ layout: 'columns', pack: 'end', class: { inner: 'md:grid-cols-[1fr_repeat(var(--footer-columns),auto)] md:gap-x-[var(--footer-gap,2.5rem)] md:[&>div:first-child]:col-span-1' } },
|
|
34
|
+
{ layout: 'columns', pack: 'end', narrow: 'row', class: { inner: '[&>div:first-child]:col-span-full' } },
|
|
28
35
|
],
|
|
29
|
-
defaultVariants: { layout: 'simple', tone: 'default', align: 'start' },
|
|
36
|
+
defaultVariants: { layout: 'simple', tone: 'default', align: 'start', pack: 'spread', narrow: 'stack' },
|
|
30
37
|
})
|
|
31
38
|
|
|
32
39
|
interface Props {
|
|
@@ -48,10 +55,22 @@ interface Props {
|
|
|
48
55
|
layout?: 'simple' | 'columns' | undefined
|
|
49
56
|
tone?: 'default' | 'muted' | 'inverse' | undefined
|
|
50
57
|
align?: 'start' | 'center' | undefined
|
|
58
|
+
/** `columns` layout only: `end` packs the link columns at the end edge, right-aligned, instead of spreading them. */
|
|
59
|
+
pack?: 'spread' | 'end' | undefined
|
|
60
|
+
/** Packed columns only: the space between columns, a CSS length (`98px`). */
|
|
61
|
+
packGap?: string | undefined
|
|
62
|
+
/** Packed columns only: below `md`, `stack` (one column) or `row` (still side by side from the start edge, under the brand). */
|
|
63
|
+
narrow?: 'stack' | 'row' | undefined
|
|
64
|
+
/** Packed columns in a `row` only: the space between them below `md`, a CSS length. */
|
|
65
|
+
packGapNarrow?: string | undefined
|
|
66
|
+
/** The links' font size, a CSS length (`17.88px`); absent, the footer's own. */
|
|
67
|
+
linkSize?: string | undefined
|
|
51
68
|
}
|
|
52
69
|
|
|
53
|
-
const { siteName, tagline, columns = [], links = [], social = [], contact, copyright, consentLabel, navLabel = 'Footer', layout = 'simple', tone, align } = Astro.props
|
|
54
|
-
const { root, inner, muted, link } = footer({ layout, tone, align })
|
|
70
|
+
const { siteName, tagline, columns = [], links = [], social = [], contact, copyright, consentLabel, navLabel = 'Footer', layout = 'simple', tone, align, pack, packGap, narrow, packGapNarrow, linkSize } = Astro.props
|
|
71
|
+
const { root, inner, muted, link } = footer({ layout, tone, align, pack: layout === 'columns' ? pack : undefined, narrow: layout === 'columns' && pack === 'end' ? narrow : undefined })
|
|
72
|
+
// Custom properties the packed columns and sized links read; none when none is set.
|
|
73
|
+
const vars = [layout === 'columns' ? `--footer-columns: ${Math.max(columns.length, 1)}` : '', layout === 'columns' && pack === 'end' && packGap ? `--footer-gap: ${packGap}` : '', layout === 'columns' && pack === 'end' && narrow === 'row' && packGapNarrow ? `--footer-gap-narrow: ${packGapNarrow}` : '', linkSize ? `--footer-link-size: ${linkSize}` : ''].filter(Boolean).join('; ')
|
|
55
74
|
const year = String(new Date().getFullYear())
|
|
56
75
|
const phoneHref = contact?.phone?.replace(/[^\d+]/g, '')
|
|
57
76
|
const hasContact = Boolean(contact?.address || contact?.phone || contact?.email)
|
|
@@ -59,7 +78,7 @@ const line = copyright?.replaceAll('{year}', year) ?? `© ${year} ${siteName}`
|
|
|
59
78
|
---
|
|
60
79
|
<!-- The cookie settings control is a button, not a link: the Consent component's listener reopens its bar on any [data-kit-consent-open]. -->
|
|
61
80
|
<footer class={root()}>
|
|
62
|
-
<div class={inner()} data-kit-footer style={
|
|
81
|
+
<div class:list={[inner(), linkSize && '[&_nav_a]:text-[length:var(--footer-link-size)]']} data-kit-footer style={vars || undefined}>
|
|
63
82
|
<div class="flex flex-col gap-3">
|
|
64
83
|
<p class="text-base font-semibold" data-kit-brand>{siteName}</p>
|
|
65
84
|
{tagline && <p class={muted()} data-kit-tagline>{tagline}</p>}
|
|
@@ -3,5 +3,7 @@
|
|
|
3
3
|
{ "name": "columns-inverse", "props": { "siteName": "Northwind Studio", "tagline": "Calm, fast websites for teams who write.", "layout": "columns", "tone": "inverse", "copyright": "© 2026 Northwind Studio", "columns": [{ "title": "Studio", "links": [{ "label": "About", "href": "/about/" }, { "label": "Team", "href": "/about/team/" }] }, { "title": "Journal", "links": [{ "label": "Guides", "href": "/category/guides/" }, { "label": "News", "href": "/category/news/" }] }, { "title": "Contact", "links": [{ "label": "Email", "href": "mailto:hello@example.com" }] }], "social": [{ "label": "GitHub", "href": "https://github.com/contentrain" }, { "label": "Mastodon", "href": "https://mastodon.social/@contentrain" }] } },
|
|
4
4
|
{ "name": "muted", "props": { "siteName": "Northwind", "tone": "muted", "copyright": "© 2026 Northwind", "links": [{ "label": "Imprint", "href": "/imprint/" }] } },
|
|
5
5
|
{ "name": "centered", "props": { "siteName": "Golden Agency", "tagline": "Websites for makers", "align": "center", "copyright": "© 2026 Golden Agency", "links": [{ "label": "Services", "href": "/services/" }, { "label": "Contact", "href": "/contact/" }], "social": [{ "label": "Instagram", "href": "https://instagram.com/" }] } },
|
|
6
|
-
{ "name": "consent-settings", "props": { "siteName": "Golden Agency", "copyright": "© 2026 Golden Agency", "consentLabel": "Cookie settings", "links": [{ "label": "Privacy", "href": "/privacy/" }] } }
|
|
6
|
+
{ "name": "consent-settings", "props": { "siteName": "Golden Agency", "copyright": "© 2026 Golden Agency", "consentLabel": "Cookie settings", "links": [{ "label": "Privacy", "href": "/privacy/" }] } },
|
|
7
|
+
{ "name": "columns-end", "props": { "siteName": "Golden Works", "tagline": "Websites for makers", "layout": "columns", "pack": "end", "packGap": "128px", "linkSize": "17.88px", "copyright": "© 2026 Golden Works", "columns": [{ "label": "Studio", "links": [{ "label": "About", "href": "/about/" }, { "label": "Work", "href": "/work/" }] }, { "label": "Contact", "links": [{ "label": "Email", "href": "mailto:hello@example.com" }, { "label": "Press", "href": "/press/" }] }] } },
|
|
8
|
+
{ "name": "columns-end-row", "props": { "siteName": "Golden Works", "layout": "columns", "pack": "end", "narrow": "row", "packGap": "128px", "packGapNarrow": "48px", "linkSize": "17.88px", "copyright": "© 2026 Golden Works", "columns": [{ "label": "Studio", "links": [{ "label": "About", "href": "/about/" }, { "label": "Work", "href": "/work/" }] }, { "label": "Contact", "links": [{ "label": "Email", "href": "mailto:hello@example.com" }] }] } }
|
|
7
9
|
]
|
|
@@ -32,6 +32,22 @@
|
|
|
32
32
|
],
|
|
33
33
|
"default": "start",
|
|
34
34
|
"description": "start: brand and links to the sides (left-aligned on phones). center: everything centred in one column, as themes with a centred footer print it."
|
|
35
|
+
},
|
|
36
|
+
"pack": {
|
|
37
|
+
"options": [
|
|
38
|
+
"spread",
|
|
39
|
+
"end"
|
|
40
|
+
],
|
|
41
|
+
"default": "spread",
|
|
42
|
+
"description": "columns layout only. spread: the link columns share the footer's width after the brand column. end: they are packed at the end edge at their own width, as a theme whose footer is the brand left and its menus on the right."
|
|
43
|
+
},
|
|
44
|
+
"narrow": {
|
|
45
|
+
"options": [
|
|
46
|
+
"stack",
|
|
47
|
+
"row"
|
|
48
|
+
],
|
|
49
|
+
"default": "stack",
|
|
50
|
+
"description": "Packed columns only, below the md breakpoint. stack: one column. row: still side by side from the start edge, under the brand."
|
|
35
51
|
}
|
|
36
52
|
},
|
|
37
53
|
"props": {
|
|
@@ -119,6 +135,18 @@
|
|
|
119
135
|
"navLabel": {
|
|
120
136
|
"type": "string",
|
|
121
137
|
"description": "Accessible name of the footer navigation (ui-strings nav.footer)."
|
|
138
|
+
},
|
|
139
|
+
"packGap": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"description": "Packed columns only: the space between columns, a CSS length such as 98px."
|
|
142
|
+
},
|
|
143
|
+
"packGapNarrow": {
|
|
144
|
+
"type": "string",
|
|
145
|
+
"description": "Packed columns in a row only: the space between them below the md breakpoint, a CSS length."
|
|
146
|
+
},
|
|
147
|
+
"linkSize": {
|
|
148
|
+
"type": "string",
|
|
149
|
+
"description": "Font size of the footer's links, a CSS length such as 17.88px; absent, the footer's own."
|
|
122
150
|
}
|
|
123
151
|
},
|
|
124
152
|
"slots": {},
|
package/mapping/gutenberg.json
CHANGED
|
@@ -552,7 +552,11 @@
|
|
|
552
552
|
},
|
|
553
553
|
"when": {
|
|
554
554
|
"position": "first",
|
|
555
|
-
"columns": 1
|
|
555
|
+
"columns": 1,
|
|
556
|
+
"order": [
|
|
557
|
+
"title",
|
|
558
|
+
"media"
|
|
559
|
+
]
|
|
556
560
|
},
|
|
557
561
|
"slots": {
|
|
558
562
|
"title": {
|
|
@@ -567,11 +571,16 @@
|
|
|
567
571
|
"button": {
|
|
568
572
|
"match": "core/button",
|
|
569
573
|
"max": 2
|
|
574
|
+
},
|
|
575
|
+
"media": {
|
|
576
|
+
"match": "core/image",
|
|
577
|
+
"max": 1
|
|
570
578
|
}
|
|
571
579
|
},
|
|
572
580
|
"props": {
|
|
573
581
|
"heading": "@title dom:",
|
|
574
|
-
"lead": "@lead dom:"
|
|
582
|
+
"lead": "@lead dom:",
|
|
583
|
+
"image": "@media img:img"
|
|
575
584
|
},
|
|
576
585
|
"into": "actions",
|
|
577
586
|
"each": "@button",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentrain/astro-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Copy-in Astro components for Contentrain sites (shadcn model): typed props, tailwind-variants, zero JavaScript by default — with a machine-readable catalog",
|
|
6
6
|
"type": "module",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"mapping"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@contentrain/types": "1.
|
|
45
|
+
"@contentrain/types": "1.38.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/node": "^22.10.0",
|