@contentrain/astro-kit 0.4.0 → 0.6.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 (71) hide show
  1. package/README.md +2 -0
  2. package/catalog.json +1519 -165
  3. package/components/_shared/KitImage.astro +10 -4
  4. package/components/_shared/image.ts +14 -0
  5. package/components/_shared/types.ts +2 -1
  6. package/components/announcement/Announcement.astro +53 -0
  7. package/components/announcement/fixtures.json +6 -0
  8. package/components/announcement/meta.json +53 -0
  9. package/components/card-grid/CardGrid.astro +5 -3
  10. package/components/card-grid/meta.json +25 -11
  11. package/components/consent/Consent.astro +87 -0
  12. package/components/consent/fixtures.json +4 -0
  13. package/components/consent/meta.json +67 -0
  14. package/components/contact-details/ContactDetails.astro +74 -0
  15. package/components/contact-details/fixtures.json +4 -0
  16. package/components/contact-details/meta.json +105 -0
  17. package/components/contact-form/ContactForm.astro +22 -6
  18. package/components/contact-form/fixtures.json +2 -1
  19. package/components/contact-form/meta.json +7 -6
  20. package/components/cta/meta.json +4 -4
  21. package/components/faq/Faq.astro +1 -1
  22. package/components/faq/meta.json +7 -7
  23. package/components/feature-list/FeatureList.astro +85 -0
  24. package/components/feature-list/fixtures.json +129 -0
  25. package/components/feature-list/meta.json +118 -0
  26. package/components/footer/Footer.astro +15 -7
  27. package/components/footer/fixtures.json +3 -1
  28. package/components/footer/meta.json +12 -0
  29. package/components/gallery/Gallery.astro +7 -3
  30. package/components/gallery/meta.json +6 -6
  31. package/components/header/Header.astro +6 -4
  32. package/components/header/fixtures.json +2 -1
  33. package/components/hero/meta.json +30 -8
  34. package/components/logo-cloud/LogoCloud.astro +69 -0
  35. package/components/logo-cloud/fixtures.json +139 -0
  36. package/components/logo-cloud/meta.json +107 -0
  37. package/components/nav/Nav.astro +11 -4
  38. package/components/nav/fixtures.json +1 -0
  39. package/components/nav/meta.json +8 -0
  40. package/components/newsletter/meta.json +12 -0
  41. package/components/pricing/Pricing.astro +94 -0
  42. package/components/pricing/fixtures.json +6 -0
  43. package/components/pricing/meta.json +133 -0
  44. package/components/prose/Prose.astro +7 -3
  45. package/components/prose/fixtures.json +2 -1
  46. package/components/prose/meta.json +5 -2
  47. package/components/slider/Slider.astro +15 -3
  48. package/components/slider/meta.json +8 -8
  49. package/components/split/Split.astro +64 -0
  50. package/components/split/fixtures.json +6 -0
  51. package/components/split/meta.json +154 -0
  52. package/components/stats/Stats.astro +66 -0
  53. package/components/stats/fixtures.json +98 -0
  54. package/components/stats/meta.json +113 -0
  55. package/components/steps/Steps.astro +77 -0
  56. package/components/steps/fixtures.json +5 -0
  57. package/components/steps/meta.json +105 -0
  58. package/components/team/Team.astro +82 -0
  59. package/components/team/fixtures.json +5 -0
  60. package/components/team/meta.json +116 -0
  61. package/components/testimonial/Testimonial.astro +5 -3
  62. package/components/testimonial/meta.json +21 -20
  63. package/dist/index.d.mts +115 -2
  64. package/dist/index.d.mts.map +1 -1
  65. package/dist/index.mjs +175 -3
  66. package/dist/index.mjs.map +1 -1
  67. package/mapping/classic.json +51 -6
  68. package/mapping/divi.json +359 -9
  69. package/mapping/elementor.json +581 -8
  70. package/mapping/gutenberg.json +420 -4
  71. package/package.json +2 -2
@@ -4,18 +4,18 @@
4
4
  "description": "Images in a square grid or in masonry columns, with optional captions. A click shows the image large in a native popover (no script), opens the image file, or does nothing.",
5
5
  "category": "section",
6
6
  "uses": [],
7
- "shared": ["KitImage.astro", "Section.astro", "types.ts"],
7
+ "shared": ["KitImage.astro", "Section.astro", "image.ts", "types.ts"],
8
8
  "variants": {
9
9
  "layout": { "options": ["grid", "masonry"], "default": "grid", "description": "grid: square crops in rows. masonry: columns that keep each image's shape." },
10
10
  "columns": { "options": ["2", "3", "4"], "default": "3", "description": "Columns on wide screens; phones show two." },
11
11
  "open": { "options": ["popover", "link", "none"], "default": "popover", "description": "popover: the image opens large in place (Popover API; Escape or a click outside closes it). link: the thumbnail links to the image file (the WordPress 'link to media file'). none: images only." }
12
12
  },
13
13
  "props": {
14
- "items": { "type": "array", "required": true, "items": { "type": "object", "fields": { "image": { "type": "object", "required": true, "fields": { "src": { "type": "image", "required": true }, "alt": { "type": "string", "required": true }, "width": { "type": "integer" }, "height": { "type": "integer" } } }, "caption": { "type": "string" } } }, "description": "The images in order (core/gallery inner images, Elementor gallery items, Divi gallery_ids)." },
15
- "heading": { "type": "string", "description": "Section heading above the images." },
16
- "closeLabel": { "type": "string", "description": "Text of the viewer's close button (ui-strings gallery.close)." },
17
- "tone": { "type": "select", "options": ["default", "muted", "inverse", "accent"], "description": "Section background." },
18
- "id": { "type": "string", "description": "Section id, unique per page: viewer ids derive from it (`<id>-image-<n>`)." }
14
+ "items": { "type": "array", "label": "Images", "required": true, "items": { "type": "object", "fields": { "image": { "type": "image", "label": "Image", "required": true, "description": "The image." }, "imageAlt": { "type": "string", "label": "Image description", "description": "What the image shows, for readers who cannot see it." }, "caption": { "type": "string", "label": "Caption", "description": "Caption under the enlarged image." } } }, "description": "The images in order (core/gallery inner images, Elementor gallery items, Divi gallery_ids)." },
15
+ "heading": { "type": "string", "label": "Heading", "description": "Section heading above the images." },
16
+ "closeLabel": { "type": "string", "content": false, "description": "Text of the viewer's close button (ui-strings gallery.close)." },
17
+ "tone": { "type": "select", "options": ["default", "muted", "inverse", "accent"], "content": false, "description": "Section background." },
18
+ "id": { "type": "string", "content": false, "description": "Section id, unique per page: viewer ids derive from it (`<id>-image-<n>`)." }
19
19
  },
20
20
  "slots": {},
21
21
  "js": "none",
@@ -53,12 +53,14 @@ interface Props {
53
53
 
54
54
  const { siteName, tagline, brandSize, linkNav, logo, showName = true, homeHref = '/', items, action, navLabel, menuLabel, closeLabel, layout, tone, position } = Astro.props
55
55
  const { root, inner, brand } = header({ layout, tone, position })
56
+ // A tagline under the name keeps its line on a phone, as themes print it: the navigation wraps below.
57
+ const wrap = tagline ? 'flex-wrap md:flex-nowrap' : undefined
56
58
  ---
57
59
  <header class={root()}>
58
- <div class={inner()}>
60
+ <div class={inner({ class: wrap })}>
59
61
  {tagline
60
62
  ? (
61
- <div class="flex flex-col gap-1">
63
+ <div class="flex min-w-0 basis-full flex-col gap-1 md:basis-auto">
62
64
  <a href={homeHref} class={brand()} aria-label={showName ? undefined : siteName} style={brandSize ? `font-size: ${brandSize}` : undefined} data-kit-brand>
63
65
  {logo && <KitImage image={logo} priority class="h-8 w-auto" sizes="160px" />}
64
66
  {showName && <span>{siteName}</span>}
@@ -72,8 +74,8 @@ const { root, inner, brand } = header({ layout, tone, position })
72
74
  {showName && <span>{siteName}</span>}
73
75
  </a>
74
76
  )}
75
- <div class:list={['flex items-center gap-4', layout === 'centered' ? 'justify-center' : 'ml-auto', linkNav && 'text-[color:var(--color-link,var(--color-accent))]']}>
76
- <Nav items={items} label={navLabel} menuLabel={menuLabel} closeLabel={closeLabel} part="nav-header" align={layout === 'centered' ? 'center' : 'end'} />
77
+ <div class:list={['flex items-center gap-4', layout === 'centered' ? 'justify-center' : 'ml-auto']}>
78
+ <Nav items={items} label={navLabel} menuLabel={menuLabel} closeLabel={closeLabel} part="nav-header" color={linkNav ? 'link' : 'current'} align={layout === 'centered' ? 'center' : 'end'} />
77
79
  {action && <Button action={action} size="sm" class="hidden md:inline-flex" />}
78
80
  </div>
79
81
  </div>
@@ -121,5 +121,6 @@
121
121
  }
122
122
  ]
123
123
  }
124
- }
124
+ },
125
+ { "name": "tagline", "props": { "siteName": "Golden Agency", "tagline": "Websites that sell what you make", "items": [{ "label": "Home", "href": "/" }, { "label": "Services", "href": "/services/" }, { "label": "Contact", "href": "/contact/" }], "menuLabel": "Menu", "closeLabel": "Close" } }
125
126
  ]
@@ -42,6 +42,7 @@
42
42
  "props": {
43
43
  "heading": {
44
44
  "type": "string",
45
+ "label": "Heading",
45
46
  "required": true,
46
47
  "description": "The main heading (Cover/Group heading, Elementor heading, Divi header title)."
47
48
  },
@@ -52,39 +53,51 @@
52
53
  "2"
53
54
  ],
54
55
  "default": "1",
56
+ "content": false,
55
57
  "description": "Heading level: 1 when the hero opens the page, 2 when the page already has an h1."
56
58
  },
57
59
  "eyebrow": {
58
60
  "type": "string",
61
+ "label": "Eyebrow",
59
62
  "description": "Short line above the heading."
60
63
  },
61
64
  "lead": {
62
65
  "type": "text",
66
+ "label": "Lead",
63
67
  "description": "Paragraph under the heading."
64
68
  },
65
69
  "actions": {
66
70
  "type": "array",
71
+ "label": "Buttons",
67
72
  "items": {
68
73
  "type": "object",
69
74
  "fields": {
70
75
  "label": {
71
76
  "type": "string",
72
- "required": true
77
+ "label": "Label",
78
+ "required": true,
79
+ "description": "The button text."
73
80
  },
74
81
  "href": {
75
82
  "type": "url",
76
- "required": true
83
+ "label": "Link",
84
+ "required": true,
85
+ "description": "Where the button goes: a page on this site or a full address."
77
86
  },
78
87
  "newTab": {
79
- "type": "boolean"
88
+ "type": "boolean",
89
+ "label": "Open in a new tab",
90
+ "description": "Open the link in a new tab (an external site the reader should not leave for)."
80
91
  },
81
92
  "style": {
82
93
  "type": "select",
94
+ "label": "Style",
83
95
  "options": [
84
96
  "primary",
85
97
  "secondary",
86
98
  "ghost"
87
- ]
99
+ ],
100
+ "description": "primary for the main action, secondary or ghost for the ones beside it."
88
101
  }
89
102
  }
90
103
  },
@@ -92,26 +105,35 @@
92
105
  },
93
106
  "image": {
94
107
  "type": "object",
108
+ "label": "Image",
95
109
  "fields": {
96
110
  "src": {
97
111
  "type": "image",
98
- "required": true
112
+ "label": "Image",
113
+ "required": true,
114
+ "description": "The image file."
99
115
  },
100
116
  "alt": {
101
117
  "type": "string",
102
- "required": true
118
+ "label": "Image description",
119
+ "description": "What the image shows, for readers who cannot see it; empty when it is decoration."
103
120
  },
104
121
  "width": {
105
- "type": "integer"
122
+ "type": "integer",
123
+ "label": "Width",
124
+ "description": "Width in pixels, as uploaded."
106
125
  },
107
126
  "height": {
108
- "type": "integer"
127
+ "type": "integer",
128
+ "label": "Height",
129
+ "description": "Height in pixels, as uploaded."
109
130
  }
110
131
  },
111
132
  "description": "Hero image; loaded first (the page's largest image)."
112
133
  },
113
134
  "id": {
114
135
  "type": "string",
136
+ "content": false,
115
137
  "description": "Anchor id of the section; the heading gets `<id>-title`."
116
138
  }
117
139
  },
@@ -0,0 +1,69 @@
1
+ ---
2
+ // A grid of client or partner logos, each optionally linked, under an
3
+ // optional heading.
4
+ import { tv } from 'tailwind-variants'
5
+ import KitImage from '../_shared/KitImage.astro'
6
+ import Section, { type Tone } from '../_shared/Section.astro'
7
+ import { imageOf, type ImageSource } from '../_shared/image'
8
+
9
+ const cloud = tv({
10
+ slots: {
11
+ heading: 'mb-8 text-center text-sm font-semibold tracking-wide uppercase opacity-80',
12
+ list: 'grid grid-cols-2 items-center gap-x-8 gap-y-10 sm:grid-cols-3',
13
+ item: 'flex items-center justify-center',
14
+ logo: 'h-10 w-auto max-w-full object-contain transition duration-200',
15
+ },
16
+ variants: {
17
+ columns: {
18
+ '2': { list: 'sm:grid-cols-2' },
19
+ '3': { list: 'md:grid-cols-3' },
20
+ '4': { list: 'md:grid-cols-4' },
21
+ },
22
+ style: {
23
+ plain: {},
24
+ // Colour comes back on hover and on keyboard focus of the logo's link.
25
+ grayscale: { logo: 'opacity-70 grayscale group-hover:opacity-100 group-hover:grayscale-0 group-focus-visible:opacity-100 group-focus-visible:grayscale-0' },
26
+ },
27
+ tone: { default: {}, muted: {}, inverse: {}, accent: { heading: 'opacity-100' } },
28
+ },
29
+ defaultVariants: { columns: '4', style: 'plain', tone: 'default' },
30
+ })
31
+
32
+ interface Item {
33
+ /** The logo's address (or, until 0.7, an `ImageInput`). */
34
+ image: ImageSource
35
+ /** The company's name, read in place of the logo. */
36
+ imageAlt: string
37
+ href?: string | undefined
38
+ }
39
+
40
+ interface Props {
41
+ heading?: string | undefined
42
+ items: Item[]
43
+ columns?: '2' | '3' | '4' | undefined
44
+ style?: 'plain' | 'grayscale' | undefined
45
+ tone?: Tone | undefined
46
+ id?: string | undefined
47
+ }
48
+
49
+ const { heading, items, columns, style, tone, id } = Astro.props
50
+ const s = cloud({ columns, style, tone })
51
+ const headingId = heading && id ? `${id}-title` : undefined
52
+ ---
53
+ <Section tone={tone} id={id} aria-labelledby={headingId}>
54
+ {heading && <h2 id={headingId} class={s.heading()}>{heading}</h2>}
55
+ <ul class={s.list()}>
56
+ {items.map(item => {
57
+ const image = imageOf(item.image, item.imageAlt)
58
+ if (!image) return null
59
+ const logo = <KitImage image={image} sizes="160px" class={s.logo()} />
60
+ return (
61
+ <li class={s.item()}>
62
+ {item.href
63
+ ? <a href={item.href} class="group rounded-sm focus-visible:outline-2 focus-visible:outline-offset-4">{logo}</a>
64
+ : <span class="group">{logo}</span>}
65
+ </li>
66
+ )
67
+ })}
68
+ </ul>
69
+ </Section>
@@ -0,0 +1,139 @@
1
+ [
2
+ {
3
+ "name": "four-plain",
4
+ "props": {
5
+ "heading": "Trusted by",
6
+ "items": [
7
+ {
8
+ "image": "/kit-fixtures/logo.svg",
9
+ "imageAlt": "Company 1",
10
+ "href": "https://example.com"
11
+ },
12
+ {
13
+ "image": "/kit-fixtures/logo.svg",
14
+ "imageAlt": "Company 2"
15
+ },
16
+ {
17
+ "image": "/kit-fixtures/logo.svg",
18
+ "imageAlt": "Company 3",
19
+ "href": "https://example.com"
20
+ },
21
+ {
22
+ "image": "/kit-fixtures/logo.svg",
23
+ "imageAlt": "Company 4"
24
+ },
25
+ {
26
+ "image": "/kit-fixtures/logo.svg",
27
+ "imageAlt": "Company 5",
28
+ "href": "https://example.com"
29
+ },
30
+ {
31
+ "image": "/kit-fixtures/logo.svg",
32
+ "imageAlt": "Company 6"
33
+ },
34
+ {
35
+ "image": "/kit-fixtures/logo.svg",
36
+ "imageAlt": "Company 7",
37
+ "href": "https://example.com"
38
+ },
39
+ {
40
+ "image": "/kit-fixtures/logo.svg",
41
+ "imageAlt": "Company 8"
42
+ }
43
+ ]
44
+ }
45
+ },
46
+ {
47
+ "name": "three-grayscale-muted",
48
+ "props": {
49
+ "heading": "Our partners",
50
+ "items": [
51
+ {
52
+ "image": "/kit-fixtures/logo.svg",
53
+ "imageAlt": "Company 1",
54
+ "href": "https://example.com"
55
+ },
56
+ {
57
+ "image": "/kit-fixtures/logo.svg",
58
+ "imageAlt": "Company 2"
59
+ },
60
+ {
61
+ "image": "/kit-fixtures/logo.svg",
62
+ "imageAlt": "Company 3",
63
+ "href": "https://example.com"
64
+ },
65
+ {
66
+ "image": "/kit-fixtures/logo.svg",
67
+ "imageAlt": "Company 4"
68
+ },
69
+ {
70
+ "image": "/kit-fixtures/logo.svg",
71
+ "imageAlt": "Company 5",
72
+ "href": "https://example.com"
73
+ },
74
+ {
75
+ "image": "/kit-fixtures/logo.svg",
76
+ "imageAlt": "Company 6"
77
+ }
78
+ ],
79
+ "columns": "3",
80
+ "style": "grayscale",
81
+ "tone": "muted"
82
+ }
83
+ },
84
+ {
85
+ "name": "two-inverse",
86
+ "props": {
87
+ "items": [
88
+ {
89
+ "image": "/kit-fixtures/logo.svg",
90
+ "imageAlt": "Company 1",
91
+ "href": "https://example.com"
92
+ },
93
+ {
94
+ "image": "/kit-fixtures/logo.svg",
95
+ "imageAlt": "Company 2"
96
+ },
97
+ {
98
+ "image": "/kit-fixtures/logo.svg",
99
+ "imageAlt": "Company 3",
100
+ "href": "https://example.com"
101
+ },
102
+ {
103
+ "image": "/kit-fixtures/logo.svg",
104
+ "imageAlt": "Company 4"
105
+ }
106
+ ],
107
+ "columns": "2",
108
+ "tone": "inverse"
109
+ }
110
+ },
111
+ {
112
+ "name": "accent",
113
+ "props": {
114
+ "heading": "Featured in",
115
+ "items": [
116
+ {
117
+ "image": "/kit-fixtures/logo.svg",
118
+ "imageAlt": "Company 1",
119
+ "href": "https://example.com"
120
+ },
121
+ {
122
+ "image": "/kit-fixtures/logo.svg",
123
+ "imageAlt": "Company 2"
124
+ },
125
+ {
126
+ "image": "/kit-fixtures/logo.svg",
127
+ "imageAlt": "Company 3",
128
+ "href": "https://example.com"
129
+ },
130
+ {
131
+ "image": "/kit-fixtures/logo.svg",
132
+ "imageAlt": "Company 4"
133
+ }
134
+ ],
135
+ "tone": "accent",
136
+ "style": "grayscale"
137
+ }
138
+ }
139
+ ]
@@ -0,0 +1,107 @@
1
+ {
2
+ "id": "logo-cloud",
3
+ "name": "Logo cloud",
4
+ "description": "A grid of client or partner logos, each optionally linked, under an optional heading (\"Trusted by\").",
5
+ "category": "section",
6
+ "uses": [],
7
+ "shared": [
8
+ "KitImage.astro",
9
+ "Section.astro",
10
+ "image.ts",
11
+ "types.ts"
12
+ ],
13
+ "variants": {
14
+ "columns": {
15
+ "options": [
16
+ "2",
17
+ "3",
18
+ "4"
19
+ ],
20
+ "default": "4",
21
+ "description": "Logos per row on wide screens; two on phones, three on tablets."
22
+ },
23
+ "style": {
24
+ "options": [
25
+ "plain",
26
+ "grayscale"
27
+ ],
28
+ "default": "plain",
29
+ "description": "plain: logos in their own colours. grayscale: muted grey, full colour on hover or focus."
30
+ },
31
+ "tone": {
32
+ "options": [
33
+ "default",
34
+ "muted",
35
+ "inverse",
36
+ "accent"
37
+ ],
38
+ "default": "default",
39
+ "description": "Section background."
40
+ }
41
+ },
42
+ "props": {
43
+ "heading": {
44
+ "type": "string",
45
+ "label": "Heading",
46
+ "description": "Line above the logos (Trusted by, Our partners)."
47
+ },
48
+ "items": {
49
+ "type": "array",
50
+ "label": "Logos",
51
+ "required": true,
52
+ "items": {
53
+ "type": "object",
54
+ "fields": {
55
+ "image": {
56
+ "type": "image",
57
+ "label": "Logo",
58
+ "required": true,
59
+ "description": "The logo file."
60
+ },
61
+ "imageAlt": {
62
+ "type": "string",
63
+ "label": "Name",
64
+ "required": true,
65
+ "description": "The company's name, read in place of the logo."
66
+ },
67
+ "href": {
68
+ "type": "url",
69
+ "label": "Link",
70
+ "description": "The company's site, when the logo links there."
71
+ }
72
+ }
73
+ },
74
+ "description": "The logos, in order (a Gutenberg gallery or columns of logos, Elementor image carousel/gallery of logos, Divi images)."
75
+ },
76
+ "id": {
77
+ "type": "string",
78
+ "content": false,
79
+ "description": "Anchor id of the section; the heading gets `<id>-title`."
80
+ }
81
+ },
82
+ "slots": {},
83
+ "js": "none",
84
+ "dependencies": {},
85
+ "sources": {
86
+ "gutenberg": [
87
+ "core/gallery"
88
+ ],
89
+ "elementor": [
90
+ "elementor/image-gallery",
91
+ "elementor/image-carousel"
92
+ ],
93
+ "divi": [
94
+ "divi/et_pb_gallery"
95
+ ]
96
+ },
97
+ "a11y": "A list of logos; each logo's text is the company's name, and a linked logo is one link named by it. The section is labelled by its heading.",
98
+ "pattern": {
99
+ "summary": "row of small logos, often linked",
100
+ "signals": [
101
+ "4+ images",
102
+ "small images",
103
+ "little or no text",
104
+ "optional heading"
105
+ ]
106
+ }
107
+ }
@@ -8,7 +8,7 @@ import type { NavItem } from '../_shared/types'
8
8
  const nav = tv({
9
9
  slots: {
10
10
  list: 'hidden items-center md:flex',
11
- link: 'text-current no-underline opacity-80 hover:opacity-100 aria-[current=page]:font-semibold aria-[current=page]:opacity-100',
11
+ link: 'no-underline aria-[current=page]:font-semibold',
12
12
  // hidden, not invisible: a closed submenu takes no space, so one under the last item cannot widen the page.
13
13
  sub: 'absolute top-full z-30 hidden min-w-48 rounded-lg border border-line bg-surface p-2 text-ink shadow-lg group-hover:block group-focus-within:block',
14
14
  toggle: 'inline-flex cursor-pointer list-none items-center gap-2 rounded-md px-3 py-2 text-sm font-medium hover:bg-current/10 md:hidden [&::-webkit-details-marker]:hidden',
@@ -17,8 +17,14 @@ const nav = tv({
17
17
  // Submenus open towards the page: leftwards under an end-aligned menu.
18
18
  align: { start: { list: 'justify-start', sub: 'left-0' }, end: { list: 'justify-end', sub: 'right-0' }, center: { list: 'justify-center', sub: 'left-0' } },
19
19
  density: { compact: { list: 'gap-5 text-sm' }, comfortable: { list: 'gap-8 text-base' } },
20
+ // current: the surrounding text, dimmed until hovered. link: the site's link colour at full strength, as themes that
21
+ // colour every link draw their menu; the toggle keeps the surrounding text.
22
+ color: {
23
+ current: { link: 'text-current opacity-80 hover:opacity-100 aria-[current=page]:opacity-100' },
24
+ link: { link: 'text-[color:var(--color-link,var(--color-accent))]' },
25
+ },
20
26
  },
21
- defaultVariants: { align: 'end', density: 'compact' },
27
+ defaultVariants: { align: 'end', density: 'compact', color: 'current' },
22
28
  })
23
29
 
24
30
  interface Props {
@@ -32,14 +38,15 @@ interface Props {
32
38
  mobile?: 'popover' | 'details' | undefined
33
39
  align?: 'start' | 'end' | 'center' | undefined
34
40
  density?: 'compact' | 'comfortable' | undefined
41
+ color?: 'current' | 'link' | undefined
35
42
  /** Unique per page when a page has two navigations. */
36
43
  id?: string | undefined
37
44
  /** What the navigation is, for checks that find a page's parts (`data-cr-part`, e.g. "nav-header"). */
38
45
  part?: string | undefined
39
46
  }
40
47
 
41
- const { items, label = 'Main', menuLabel = 'Menu', closeLabel = 'Close', mobile = 'popover', align, density, id = 'site-nav', part } = Astro.props
42
- const { list, link, sub, toggle } = nav({ align, density })
48
+ const { items, label = 'Main', menuLabel = 'Menu', closeLabel = 'Close', mobile = 'popover', align, density, color, id = 'site-nav', part } = Astro.props
49
+ const { list, link, sub, toggle } = nav({ align, density, color })
43
50
  const current = Astro.url.pathname
44
51
  const drawer = `${id}-drawer`
45
52
  ---
@@ -61,6 +61,7 @@
61
61
  "props": {
62
62
  "id": "fx-nav-c",
63
63
  "align": "center",
64
+ "color": "link",
64
65
  "items": [
65
66
  {
66
67
  "label": "Work",
@@ -32,6 +32,14 @@
32
32
  ],
33
33
  "default": "compact",
34
34
  "description": "Gap and text size of the inline list."
35
+ },
36
+ "color": {
37
+ "options": [
38
+ "current",
39
+ "link"
40
+ ],
41
+ "default": "current",
42
+ "description": "current: the surrounding text, dimmed until hovered. link: the site's link colour (--color-link, else the accent) at full strength."
35
43
  }
36
44
  },
37
45
  "props": {
@@ -30,11 +30,13 @@
30
30
  "props": {
31
31
  "action": {
32
32
  "type": "url",
33
+ "label": "Form address",
33
34
  "required": true,
34
35
  "description": "The provider's hosted form endpoint (Mailchimp *.list-manage.com/subscribe/post, Kit app.kit.com/forms/<n>/subscriptions, MailerLite assets.mailerlite.com/jsonp/<n>/forms/<n>/subscribe, Brevo *.sibforms.com/serve/, Buttondown buttondown.com/api/emails/embed-subscribe/). At migration the engine reads it from the source form element (`dom:form@action`) into the section's content, where it stays editable in Studio; it never passes through the fact pack or a model."
35
36
  },
36
37
  "provider": {
37
38
  "type": "select",
39
+ "label": "Email provider",
38
40
  "options": [
39
41
  "mailchimp",
40
42
  "kit",
@@ -48,44 +50,54 @@
48
50
  },
49
51
  "emailName": {
50
52
  "type": "string",
53
+ "label": "Email field name",
51
54
  "description": "Field name for the address when the provider is other or names it differently."
52
55
  },
53
56
  "askName": {
54
57
  "type": "boolean",
58
+ "label": "Ask for a name",
55
59
  "default": false,
56
60
  "description": "Ask for a first name too, when the provider takes one (the source form had a name field)."
57
61
  },
58
62
  "heading": {
59
63
  "type": "string",
64
+ "label": "Heading",
60
65
  "description": "Section heading."
61
66
  },
62
67
  "intro": {
63
68
  "type": "text",
69
+ "label": "Introduction",
64
70
  "description": "A line or two about the newsletter."
65
71
  },
66
72
  "note": {
67
73
  "type": "string",
74
+ "label": "Note",
68
75
  "description": "Small print under the form (privacy, frequency)."
69
76
  },
70
77
  "emailLabel": {
71
78
  "type": "string",
79
+ "content": false,
72
80
  "description": "ui-strings newsletter.email."
73
81
  },
74
82
  "nameLabel": {
75
83
  "type": "string",
84
+ "content": false,
76
85
  "description": "ui-strings newsletter.name."
77
86
  },
78
87
  "submitLabel": {
79
88
  "type": "string",
89
+ "content": false,
80
90
  "description": "ui-strings newsletter.submit."
81
91
  },
82
92
  "newTab": {
83
93
  "type": "boolean",
84
94
  "default": true,
95
+ "content": false,
85
96
  "description": "Open the provider's confirmation page in a new tab (the reader keeps the site)."
86
97
  },
87
98
  "id": {
88
99
  "type": "string",
100
+ "content": false,
89
101
  "description": "Section id, unique per page (two sign-ups on one page need two ids): the heading gets `<id>-title`, the inputs `<id>-email`/`<id>-name`."
90
102
  }
91
103
  },