ferst-core 0.7.7 → 0.7.9
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/bin/ferst-modules.mjs +18 -2
- package/components/BlockRenderer.astro +125 -119
- package/components/Button.astro +1 -1
- package/components/CalendarEmbed.astro +2 -1
- package/components/Card.astro +2 -0
- package/components/SiteHeader.astro +24 -0
- package/components/recipes/Accordion.astro +91 -87
- package/components/recipes/Bento.astro +7 -3
- package/components/recipes/ContactForm.astro +6 -3
- package/components/recipes/Cta.astro +5 -1
- package/components/recipes/Faq.astro +5 -1
- package/components/recipes/FeatureCards.astro +115 -112
- package/components/recipes/Hero.astro +521 -495
- package/components/recipes/LatestPosts.astro +1 -1
- package/components/recipes/MediaCards.astro +214 -213
- package/components/recipes/Notice.astro +90 -90
- package/components/recipes/Pricing.astro +7 -4
- package/components/recipes/Stats.astro +155 -152
- package/components/recipes/Steps.astro +124 -121
- package/components/recipes/Tabs.astro +138 -134
- package/components/recipes/Tiles.astro +291 -287
- package/content/blocks.ts +88 -52
- package/layouts/Base.astro +496 -484
- package/lib/inline-markdown.ts +13 -0
- package/lib/slug.ts +1 -1
- package/package.json +1 -1
- package/routes/calendar/index.astro +2 -1
|
@@ -1,112 +1,115 @@
|
|
|
1
|
-
---
|
|
2
|
-
/**
|
|
3
|
-
* FeatureCards — a Level-2 recipe: an optional section header over a responsive
|
|
4
|
-
* grid of cards, each with an optional icon, a title, text, and an optional
|
|
5
|
-
* link. Composes the Card, Icon, Heading and Button primitives.
|
|
6
|
-
*/
|
|
7
|
-
import Heading from '../blocks/Heading.astro';
|
|
8
|
-
import Card from '../Card.astro';
|
|
9
|
-
import Icon from '../Icon.astro';
|
|
10
|
-
import Button from '../Button.astro';
|
|
11
|
-
import { isIconKey } from '../../lib/icons';
|
|
12
|
-
|
|
13
|
-
import { inlineMarkdown } from '../../lib/inline-markdown';
|
|
14
|
-
interface Props {
|
|
15
|
-
title?: string;
|
|
16
|
-
intro?: string;
|
|
17
|
-
columns?: 2 | 3 | 4;
|
|
18
|
-
cards?: { icon?: string; title: string; text?: string; href?: string }[];
|
|
19
|
-
}
|
|
20
|
-
const { title, intro, columns = 3, cards = [] } = Astro.props;
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{card.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* FeatureCards — a Level-2 recipe: an optional section header over a responsive
|
|
4
|
+
* grid of cards, each with an optional icon, a title, text, and an optional
|
|
5
|
+
* link. Composes the Card, Icon, Heading and Button primitives.
|
|
6
|
+
*/
|
|
7
|
+
import Heading from '../blocks/Heading.astro';
|
|
8
|
+
import Card from '../Card.astro';
|
|
9
|
+
import Icon from '../Icon.astro';
|
|
10
|
+
import Button from '../Button.astro';
|
|
11
|
+
import { isIconKey } from '../../lib/icons';
|
|
12
|
+
|
|
13
|
+
import { inlineMarkdown } from '../../lib/inline-markdown';
|
|
14
|
+
interface Props {
|
|
15
|
+
title?: string;
|
|
16
|
+
intro?: string;
|
|
17
|
+
columns?: 2 | 3 | 4;
|
|
18
|
+
cards?: { icon?: string; title: string; text?: string; href?: string }[];
|
|
19
|
+
}
|
|
20
|
+
const { title, intro, columns = 3, cards = [] } = Astro.props;
|
|
21
|
+
// Alignment overrides (BlockLayout): the title + intro default to centred; the block's
|
|
22
|
+
// own `align`, or `headingAlign` for the title alone, overrides it from the page data.
|
|
23
|
+
const { align: blockAlign, headingAlign } = Astro.props as { align?: 'start' | 'center' | 'end'; headingAlign?: 'start' | 'center' | 'end' };
|
|
24
|
+
const headAlign = headingAlign ?? blockAlign ?? 'center';
|
|
25
|
+
// Never reserve more columns than there are cards (a lone card in a 3-col grid
|
|
26
|
+
// would strand two empty cells); `data-single` centres a solitary card.
|
|
27
|
+
const cols = Math.min(columns, Math.max(cards.length, 1)) as 1 | 2 | 3 | 4;
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<section class="b-feature-cards">
|
|
31
|
+
{(title || intro) && (
|
|
32
|
+
<div class="b-feature-cards__head" data-recipe-head data-content-align={headAlign}>
|
|
33
|
+
{title && <Heading text={title} level={2} />}
|
|
34
|
+
{intro && <p class="b-feature-cards__intro" set:html={inlineMarkdown(intro)} />}
|
|
35
|
+
</div>
|
|
36
|
+
)}
|
|
37
|
+
<div class="b-feature-cards__grid" data-cols={cols} data-single={cards.length === 1 ? 'true' : undefined}>
|
|
38
|
+
{cards.map((card) => (
|
|
39
|
+
<Card>
|
|
40
|
+
{card.icon && isIconKey(card.icon) && (
|
|
41
|
+
<span class="b-feature-cards__icon"><Icon name={card.icon} size={28} /></span>
|
|
42
|
+
)}
|
|
43
|
+
<h3 class="b-feature-cards__title">{card.title}</h3>
|
|
44
|
+
{card.text && <p class="b-feature-cards__text" set:html={inlineMarkdown(card.text)} />}
|
|
45
|
+
{card.href && (
|
|
46
|
+
<span class="b-feature-cards__cta">
|
|
47
|
+
<Button href={card.href} variant="secondary" size="sm">Learn more</Button>
|
|
48
|
+
</span>
|
|
49
|
+
)}
|
|
50
|
+
</Card>
|
|
51
|
+
))}
|
|
52
|
+
</div>
|
|
53
|
+
</section>
|
|
54
|
+
|
|
55
|
+
<style>
|
|
56
|
+
.b-feature-cards {
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: column;
|
|
59
|
+
gap: 2rem;
|
|
60
|
+
max-width: 72rem;
|
|
61
|
+
margin-inline: auto;
|
|
62
|
+
padding-inline: 1rem;
|
|
63
|
+
}
|
|
64
|
+
.b-feature-cards__head {
|
|
65
|
+
max-width: var(--max);
|
|
66
|
+
margin-inline: auto;
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
gap: 0.75rem;
|
|
70
|
+
}
|
|
71
|
+
.b-feature-cards__intro {
|
|
72
|
+
margin: 0;
|
|
73
|
+
color: var(--muted);
|
|
74
|
+
font-size: 1.0625rem;
|
|
75
|
+
line-height: 1.6;
|
|
76
|
+
}
|
|
77
|
+
.b-feature-cards__grid {
|
|
78
|
+
display: grid;
|
|
79
|
+
grid-template-columns: 1fr; /* mobile-first */
|
|
80
|
+
gap: 1.5rem;
|
|
81
|
+
}
|
|
82
|
+
@media (min-width: 48em) {
|
|
83
|
+
.b-feature-cards__grid[data-cols='2'] { grid-template-columns: repeat(2, 1fr); }
|
|
84
|
+
.b-feature-cards__grid[data-cols='3'] { grid-template-columns: repeat(3, 1fr); }
|
|
85
|
+
.b-feature-cards__grid[data-cols='4'] { grid-template-columns: repeat(2, 1fr); }
|
|
86
|
+
}
|
|
87
|
+
/* A solitary card is a centred feature, not a full-width slab. */
|
|
88
|
+
.b-feature-cards__grid[data-single] { max-width: 26rem; margin-inline: auto;
|
|
89
|
+
}
|
|
90
|
+
@media (min-width: 64em) {
|
|
91
|
+
.b-feature-cards__grid[data-cols='4'] { grid-template-columns: repeat(4, 1fr); }
|
|
92
|
+
}
|
|
93
|
+
.b-feature-cards__icon {
|
|
94
|
+
color: var(--gold);
|
|
95
|
+
margin-bottom: 0.5rem;
|
|
96
|
+
display: inline-flex;
|
|
97
|
+
}
|
|
98
|
+
.b-feature-cards__title {
|
|
99
|
+
margin: 0 0 0.5rem;
|
|
100
|
+
font-size: 1.125rem;
|
|
101
|
+
color: var(--fg);
|
|
102
|
+
}
|
|
103
|
+
.b-feature-cards__text {
|
|
104
|
+
margin: 0;
|
|
105
|
+
color: var(--muted);
|
|
106
|
+
line-height: 1.6;
|
|
107
|
+
}
|
|
108
|
+
/* Push the CTA to the bottom so a row of cards aligns its buttons regardless
|
|
109
|
+
of how much text each card has. Cards are equal height already (grid items
|
|
110
|
+
stretch), and Card is a flex column — margin-top:auto does the rest. */
|
|
111
|
+
.b-feature-cards__cta {
|
|
112
|
+
margin-top: auto;
|
|
113
|
+
padding-top: 1rem;
|
|
114
|
+
}
|
|
115
|
+
</style>
|