@buildcanada/components 0.3.3 → 0.3.5
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/dist/content/Card/Card.d.ts +62 -0
- package/dist/content/Card/Card.d.ts.map +1 -0
- package/dist/content/Card/Card.js +45 -0
- package/dist/content/Card/Card.scss +281 -0
- package/dist/content/Card/index.d.ts +3 -0
- package/dist/content/Card/index.d.ts.map +1 -0
- package/dist/content/Card/index.js +2 -0
- package/dist/content/Hero/Hero.d.ts +28 -0
- package/dist/content/Hero/Hero.d.ts.map +1 -0
- package/dist/content/Hero/Hero.js +16 -0
- package/dist/content/Hero/Hero.scss +150 -0
- package/dist/content/Hero/index.d.ts +3 -0
- package/dist/content/Hero/index.d.ts.map +1 -0
- package/dist/content/Hero/index.js +2 -0
- package/dist/content/StatBlock/StatBlock.d.ts +15 -0
- package/dist/content/StatBlock/StatBlock.d.ts.map +1 -0
- package/dist/content/StatBlock/StatBlock.js +10 -0
- package/dist/content/StatBlock/StatBlock.scss +83 -0
- package/dist/content/StatBlock/index.d.ts +3 -0
- package/dist/content/StatBlock/index.d.ts.map +1 -0
- package/dist/content/StatBlock/index.js +2 -0
- package/dist/feedback/Dialog/Dialog.d.ts +18 -0
- package/dist/feedback/Dialog/Dialog.d.ts.map +1 -0
- package/dist/feedback/Dialog/Dialog.js +33 -0
- package/dist/feedback/Dialog/Dialog.scss +158 -0
- package/dist/feedback/Dialog/index.d.ts +2 -0
- package/dist/feedback/Dialog/index.d.ts.map +1 -0
- package/dist/feedback/Dialog/index.js +1 -0
- package/dist/feedback/PopupForm/PopupForm.d.ts +24 -0
- package/dist/feedback/PopupForm/PopupForm.d.ts.map +1 -0
- package/dist/feedback/PopupForm/PopupForm.js +13 -0
- package/dist/feedback/PopupForm/PopupForm.scss +34 -0
- package/dist/feedback/PopupForm/index.d.ts +2 -0
- package/dist/feedback/PopupForm/index.d.ts.map +1 -0
- package/dist/feedback/PopupForm/index.js +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/layout/Container/Container.d.ts +11 -0
- package/dist/layout/Container/Container.d.ts.map +1 -0
- package/dist/layout/Container/Container.js +7 -0
- package/dist/layout/Container/Container.scss +40 -0
- package/dist/layout/Container/index.d.ts +3 -0
- package/dist/layout/Container/index.d.ts.map +1 -0
- package/dist/layout/Container/index.js +2 -0
- package/dist/layout/Divider/Divider.d.ts +12 -0
- package/dist/layout/Divider/Divider.d.ts.map +1 -0
- package/dist/layout/Divider/Divider.js +7 -0
- package/dist/layout/Divider/Divider.scss +117 -0
- package/dist/layout/Divider/index.d.ts +3 -0
- package/dist/layout/Divider/index.d.ts.map +1 -0
- package/dist/layout/Divider/index.js +2 -0
- package/dist/layout/Grid/Grid.d.ts +24 -0
- package/dist/layout/Grid/Grid.d.ts.map +1 -0
- package/dist/layout/Grid/Grid.js +11 -0
- package/dist/layout/Grid/Grid.scss +81 -0
- package/dist/layout/Grid/index.d.ts +3 -0
- package/dist/layout/Grid/index.d.ts.map +1 -0
- package/dist/layout/Grid/index.js +2 -0
- package/dist/layout/Section/Section.d.ts +13 -0
- package/dist/layout/Section/Section.d.ts.map +1 -0
- package/dist/layout/Section/Section.js +7 -0
- package/dist/layout/Section/Section.scss +74 -0
- package/dist/layout/Section/index.d.ts +3 -0
- package/dist/layout/Section/index.d.ts.map +1 -0
- package/dist/layout/Section/index.js +2 -0
- package/dist/layout/Stack/Stack.d.ts +18 -0
- package/dist/layout/Stack/Stack.d.ts.map +1 -0
- package/dist/layout/Stack/Stack.js +7 -0
- package/dist/layout/Stack/Stack.scss +61 -0
- package/dist/layout/Stack/index.d.ts +3 -0
- package/dist/layout/Stack/index.d.ts.map +1 -0
- package/dist/layout/Stack/index.js +2 -0
- package/dist/navigation/Footer/Footer.d.ts +31 -0
- package/dist/navigation/Footer/Footer.d.ts.map +1 -0
- package/dist/navigation/Footer/Footer.js +21 -0
- package/dist/navigation/Footer/Footer.scss +233 -0
- package/dist/navigation/Footer/index.d.ts +3 -0
- package/dist/navigation/Footer/index.d.ts.map +1 -0
- package/dist/navigation/Footer/index.js +2 -0
- package/dist/navigation/Header/Header.d.ts +23 -0
- package/dist/navigation/Header/Header.d.ts.map +1 -0
- package/dist/navigation/Header/Header.js +16 -0
- package/dist/navigation/Header/Header.scss +325 -0
- package/dist/navigation/Header/index.d.ts +3 -0
- package/dist/navigation/Header/index.d.ts.map +1 -0
- package/dist/navigation/Header/index.js +2 -0
- package/dist/primitives/Button/Button.d.ts +31 -0
- package/dist/primitives/Button/Button.d.ts.map +1 -0
- package/dist/primitives/Button/Button.js +36 -0
- package/dist/primitives/Button/Button.scss +218 -0
- package/dist/primitives/Button/index.d.ts +3 -0
- package/dist/primitives/Button/index.d.ts.map +1 -0
- package/dist/primitives/Button/index.js +2 -0
- package/dist/primitives/Checkbox/Checkbox.d.ts +13 -0
- package/dist/primitives/Checkbox/Checkbox.d.ts.map +1 -0
- package/dist/primitives/Checkbox/Checkbox.js +10 -0
- package/dist/primitives/Checkbox/Checkbox.scss +114 -0
- package/dist/primitives/Checkbox/index.d.ts +3 -0
- package/dist/primitives/Checkbox/index.d.ts.map +1 -0
- package/dist/primitives/Checkbox/index.js +2 -0
- package/dist/primitives/TextField/TextField.d.ts +22 -0
- package/dist/primitives/TextField/TextField.d.ts.map +1 -0
- package/dist/primitives/TextField/TextField.js +14 -0
- package/dist/primitives/TextField/TextField.scss +93 -0
- package/dist/primitives/TextField/index.d.ts +3 -0
- package/dist/primitives/TextField/index.d.ts.map +1 -0
- package/dist/primitives/TextField/index.js +2 -0
- package/dist/styles/fonts.scss +27 -0
- package/dist/styles/main.scss +36 -0
- package/dist/styles/tokens.scss +301 -0
- package/dist/styles/typography.scss +232 -0
- package/package.json +12 -11
- package/src/content/Card/Card.stories.tsx +389 -0
- package/src/content/Card/index.ts +2 -2
- package/src/content/Hero/Hero.stories.tsx +299 -0
- package/src/content/Hero/index.ts +2 -2
- package/src/content/StatBlock/StatBlock.stories.tsx +331 -0
- package/src/content/StatBlock/index.ts +2 -2
- package/src/feedback/Dialog/Dialog.stories.tsx +286 -0
- package/src/feedback/Dialog/index.ts +1 -1
- package/src/feedback/PopupForm/PopupForm.stories.tsx +341 -0
- package/src/feedback/PopupForm/PopupForm.tsx +2 -2
- package/src/feedback/PopupForm/index.ts +1 -1
- package/src/index.ts +15 -15
- package/src/layout/Container/Container.stories.tsx +153 -0
- package/src/layout/Container/index.ts +2 -2
- package/src/layout/Divider/Divider.stories.tsx +204 -0
- package/src/layout/Divider/index.ts +2 -2
- package/src/layout/Grid/Grid.stories.tsx +263 -0
- package/src/layout/Grid/index.ts +2 -2
- package/src/layout/Section/Section.stories.tsx +173 -0
- package/src/layout/Section/index.ts +2 -2
- package/src/layout/Stack/Stack.stories.tsx +342 -0
- package/src/layout/Stack/index.ts +2 -2
- package/src/navigation/Footer/Footer.stories.tsx +351 -0
- package/src/navigation/Footer/index.ts +2 -2
- package/src/navigation/Header/Header.stories.tsx +346 -0
- package/src/navigation/Header/index.ts +2 -2
- package/src/primitives/Button/Button.stories.tsx +300 -0
- package/src/primitives/Button/index.ts +2 -2
- package/src/primitives/Checkbox/Checkbox.stories.tsx +204 -0
- package/src/primitives/Checkbox/index.ts +2 -2
- package/src/primitives/TextField/TextField.stories.tsx +265 -0
- package/src/primitives/TextField/index.ts +2 -2
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import { within, userEvent, expect, fn } from "@storybook/test"
|
|
3
|
+
import { faLightbulb, faChartLine, faUsers, faCode } from "@fortawesome/free-solid-svg-icons"
|
|
4
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
Card,
|
|
8
|
+
CardImage,
|
|
9
|
+
CardIcon,
|
|
10
|
+
CardContent,
|
|
11
|
+
CardTitle,
|
|
12
|
+
CardDescription,
|
|
13
|
+
CardMeta,
|
|
14
|
+
CardStat,
|
|
15
|
+
CardAuthor,
|
|
16
|
+
} from "./Card"
|
|
17
|
+
|
|
18
|
+
const meta: Meta<typeof Card> = {
|
|
19
|
+
title: "Components/Content/Card",
|
|
20
|
+
component: Card,
|
|
21
|
+
parameters: {
|
|
22
|
+
docs: {
|
|
23
|
+
description: {
|
|
24
|
+
component: `
|
|
25
|
+
A composable card component with multiple variants for different content types.
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
\`\`\`tsx
|
|
30
|
+
import { Card, CardContent, CardTitle, CardDescription } from "@buildcanada/components"
|
|
31
|
+
|
|
32
|
+
<Card variant="default">
|
|
33
|
+
<CardContent>
|
|
34
|
+
<CardTitle>Card Title</CardTitle>
|
|
35
|
+
<CardDescription>Card description text.</CardDescription>
|
|
36
|
+
</CardContent>
|
|
37
|
+
</Card>
|
|
38
|
+
\`\`\`
|
|
39
|
+
|
|
40
|
+
## Variants
|
|
41
|
+
|
|
42
|
+
- **default**: Basic card for general content
|
|
43
|
+
- **project**: Card with image for project showcases
|
|
44
|
+
- **memo**: Card for articles/memos with author info
|
|
45
|
+
- **feature**: Card with icon for feature highlights
|
|
46
|
+
- **stat**: Card for displaying statistics
|
|
47
|
+
- **profile**: Card for team member profiles
|
|
48
|
+
|
|
49
|
+
## Sub-components
|
|
50
|
+
|
|
51
|
+
- \`CardImage\`: Image header for the card
|
|
52
|
+
- \`CardIcon\`: Icon container for feature cards
|
|
53
|
+
- \`CardContent\`: Main content wrapper
|
|
54
|
+
- \`CardTitle\`: Card heading
|
|
55
|
+
- \`CardDescription\`: Card body text
|
|
56
|
+
- \`CardMeta\`: Metadata like dates
|
|
57
|
+
- \`CardStat\`: Statistics display with change indicators
|
|
58
|
+
- \`CardAuthor\`: Author info with avatar
|
|
59
|
+
`,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
argTypes: {
|
|
64
|
+
variant: {
|
|
65
|
+
control: "select",
|
|
66
|
+
options: ["default", "project", "memo", "feature", "stat", "profile"],
|
|
67
|
+
description: "The visual style variant of the card",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default meta
|
|
73
|
+
type Story = StoryObj<typeof Card>
|
|
74
|
+
|
|
75
|
+
export const Default: Story = {
|
|
76
|
+
args: {
|
|
77
|
+
variant: "default",
|
|
78
|
+
children: (
|
|
79
|
+
<CardContent>
|
|
80
|
+
<CardTitle>Card Title</CardTitle>
|
|
81
|
+
<CardDescription>
|
|
82
|
+
This is a description of the card content. It provides more
|
|
83
|
+
details about the subject.
|
|
84
|
+
</CardDescription>
|
|
85
|
+
</CardContent>
|
|
86
|
+
),
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const ProjectCard: Story = {
|
|
91
|
+
args: {
|
|
92
|
+
variant: "project",
|
|
93
|
+
href: "#",
|
|
94
|
+
children: (
|
|
95
|
+
<>
|
|
96
|
+
<CardImage
|
|
97
|
+
src="https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?w=600&h=400&fit=crop"
|
|
98
|
+
alt="Modern building"
|
|
99
|
+
/>
|
|
100
|
+
<CardContent>
|
|
101
|
+
<CardTitle>Infrastructure Development</CardTitle>
|
|
102
|
+
<CardDescription>
|
|
103
|
+
A comprehensive analysis of Canada's infrastructure spending
|
|
104
|
+
and development priorities over the past decade.
|
|
105
|
+
</CardDescription>
|
|
106
|
+
<CardMeta>Published March 2024</CardMeta>
|
|
107
|
+
</CardContent>
|
|
108
|
+
</>
|
|
109
|
+
),
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const MemoCard: Story = {
|
|
114
|
+
args: {
|
|
115
|
+
variant: "memo",
|
|
116
|
+
href: "#",
|
|
117
|
+
children: (
|
|
118
|
+
<CardContent>
|
|
119
|
+
<CardTitle>The Future of Canadian Manufacturing</CardTitle>
|
|
120
|
+
<CardDescription>
|
|
121
|
+
How policy changes and technological innovation are reshaping
|
|
122
|
+
Canada's manufacturing sector for the next generation.
|
|
123
|
+
</CardDescription>
|
|
124
|
+
<CardAuthor
|
|
125
|
+
name="Sarah Johnson"
|
|
126
|
+
role="Senior Analyst"
|
|
127
|
+
avatar="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop"
|
|
128
|
+
/>
|
|
129
|
+
</CardContent>
|
|
130
|
+
),
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const FeatureCard: Story = {
|
|
135
|
+
args: {
|
|
136
|
+
variant: "feature",
|
|
137
|
+
children: (
|
|
138
|
+
<>
|
|
139
|
+
<CardIcon>
|
|
140
|
+
<FontAwesomeIcon icon={faChartLine} size="2x" />
|
|
141
|
+
</CardIcon>
|
|
142
|
+
<CardContent>
|
|
143
|
+
<CardTitle>Data-Driven Insights</CardTitle>
|
|
144
|
+
<CardDescription>
|
|
145
|
+
Access comprehensive data analysis and visualizations
|
|
146
|
+
to understand government spending patterns.
|
|
147
|
+
</CardDescription>
|
|
148
|
+
</CardContent>
|
|
149
|
+
</>
|
|
150
|
+
),
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export const StatCard: Story = {
|
|
155
|
+
args: {
|
|
156
|
+
variant: "stat",
|
|
157
|
+
children: (
|
|
158
|
+
<CardContent>
|
|
159
|
+
<CardStat
|
|
160
|
+
value="$456.2B"
|
|
161
|
+
label="Total Federal Spending"
|
|
162
|
+
change="+8.3%"
|
|
163
|
+
changeDirection="up"
|
|
164
|
+
/>
|
|
165
|
+
</CardContent>
|
|
166
|
+
),
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export const ProfileCard: Story = {
|
|
171
|
+
args: {
|
|
172
|
+
variant: "profile",
|
|
173
|
+
children: (
|
|
174
|
+
<>
|
|
175
|
+
<CardImage
|
|
176
|
+
src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=300&h=300&fit=crop"
|
|
177
|
+
alt="John Smith"
|
|
178
|
+
/>
|
|
179
|
+
<CardContent>
|
|
180
|
+
<CardTitle as="h4">John Smith</CardTitle>
|
|
181
|
+
<CardDescription>Director of Research</CardDescription>
|
|
182
|
+
<CardMeta>Ottawa, ON</CardMeta>
|
|
183
|
+
</CardContent>
|
|
184
|
+
</>
|
|
185
|
+
),
|
|
186
|
+
},
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Interactive test: Clickable card
|
|
190
|
+
export const ClickableCardTest: Story = {
|
|
191
|
+
args: {
|
|
192
|
+
variant: "default",
|
|
193
|
+
onClick: fn(),
|
|
194
|
+
children: (
|
|
195
|
+
<CardContent>
|
|
196
|
+
<CardTitle>Clickable Card</CardTitle>
|
|
197
|
+
<CardDescription>Click anywhere on this card.</CardDescription>
|
|
198
|
+
</CardContent>
|
|
199
|
+
),
|
|
200
|
+
},
|
|
201
|
+
play: async ({ canvasElement, args }) => {
|
|
202
|
+
const canvas = within(canvasElement)
|
|
203
|
+
const card = canvas.getByRole("button")
|
|
204
|
+
|
|
205
|
+
await expect(card).toBeInTheDocument()
|
|
206
|
+
await userEvent.click(card)
|
|
207
|
+
await expect(args.onClick).toHaveBeenCalled()
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Interactive test: Link card
|
|
212
|
+
export const LinkCardTest: Story = {
|
|
213
|
+
args: {
|
|
214
|
+
variant: "project",
|
|
215
|
+
href: "#test-link",
|
|
216
|
+
children: (
|
|
217
|
+
<CardContent>
|
|
218
|
+
<CardTitle>Link Card</CardTitle>
|
|
219
|
+
<CardDescription>This card links somewhere.</CardDescription>
|
|
220
|
+
</CardContent>
|
|
221
|
+
),
|
|
222
|
+
},
|
|
223
|
+
play: async ({ canvasElement }) => {
|
|
224
|
+
const canvas = within(canvasElement)
|
|
225
|
+
const link = canvas.getByRole("link")
|
|
226
|
+
|
|
227
|
+
await expect(link).toHaveAttribute("href", "#test-link")
|
|
228
|
+
},
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Interactive test: Card with hover
|
|
232
|
+
export const HoverCardTest: Story = {
|
|
233
|
+
args: {
|
|
234
|
+
variant: "project",
|
|
235
|
+
href: "#",
|
|
236
|
+
children: (
|
|
237
|
+
<>
|
|
238
|
+
<CardImage
|
|
239
|
+
src="https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?w=600&h=400&fit=crop"
|
|
240
|
+
alt="Building"
|
|
241
|
+
/>
|
|
242
|
+
<CardContent>
|
|
243
|
+
<CardTitle>Hover Card</CardTitle>
|
|
244
|
+
<CardDescription>Hover to see the effect.</CardDescription>
|
|
245
|
+
</CardContent>
|
|
246
|
+
</>
|
|
247
|
+
),
|
|
248
|
+
},
|
|
249
|
+
play: async ({ canvasElement }) => {
|
|
250
|
+
const canvas = within(canvasElement)
|
|
251
|
+
const card = canvas.getByRole("link")
|
|
252
|
+
|
|
253
|
+
await userEvent.hover(card)
|
|
254
|
+
// Visual check for hover state
|
|
255
|
+
},
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export const FeatureCardsGrid: Story = {
|
|
259
|
+
render: () => (
|
|
260
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))", gap: "24px" }}>
|
|
261
|
+
<Card variant="feature">
|
|
262
|
+
<CardIcon>
|
|
263
|
+
<FontAwesomeIcon icon={faChartLine} size="2x" />
|
|
264
|
+
</CardIcon>
|
|
265
|
+
<CardContent>
|
|
266
|
+
<CardTitle>Analytics</CardTitle>
|
|
267
|
+
<CardDescription>
|
|
268
|
+
Comprehensive data analysis tools for government spending.
|
|
269
|
+
</CardDescription>
|
|
270
|
+
</CardContent>
|
|
271
|
+
</Card>
|
|
272
|
+
<Card variant="feature">
|
|
273
|
+
<CardIcon>
|
|
274
|
+
<FontAwesomeIcon icon={faUsers} size="2x" />
|
|
275
|
+
</CardIcon>
|
|
276
|
+
<CardContent>
|
|
277
|
+
<CardTitle>Collaboration</CardTitle>
|
|
278
|
+
<CardDescription>
|
|
279
|
+
Work together with researchers across Canada.
|
|
280
|
+
</CardDescription>
|
|
281
|
+
</CardContent>
|
|
282
|
+
</Card>
|
|
283
|
+
<Card variant="feature">
|
|
284
|
+
<CardIcon>
|
|
285
|
+
<FontAwesomeIcon icon={faLightbulb} size="2x" />
|
|
286
|
+
</CardIcon>
|
|
287
|
+
<CardContent>
|
|
288
|
+
<CardTitle>Insights</CardTitle>
|
|
289
|
+
<CardDescription>
|
|
290
|
+
Discover patterns and trends in public data.
|
|
291
|
+
</CardDescription>
|
|
292
|
+
</CardContent>
|
|
293
|
+
</Card>
|
|
294
|
+
<Card variant="feature">
|
|
295
|
+
<CardIcon>
|
|
296
|
+
<FontAwesomeIcon icon={faCode} size="2x" />
|
|
297
|
+
</CardIcon>
|
|
298
|
+
<CardContent>
|
|
299
|
+
<CardTitle>Open Source</CardTitle>
|
|
300
|
+
<CardDescription>
|
|
301
|
+
All our tools and data are freely available.
|
|
302
|
+
</CardDescription>
|
|
303
|
+
</CardContent>
|
|
304
|
+
</Card>
|
|
305
|
+
</div>
|
|
306
|
+
),
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export const StatCardsRow: Story = {
|
|
310
|
+
render: () => (
|
|
311
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))", gap: "16px" }}>
|
|
312
|
+
<Card variant="stat">
|
|
313
|
+
<CardContent>
|
|
314
|
+
<CardStat
|
|
315
|
+
value="$456.2B"
|
|
316
|
+
label="Federal Spending"
|
|
317
|
+
change="+8.3%"
|
|
318
|
+
changeDirection="up"
|
|
319
|
+
/>
|
|
320
|
+
</CardContent>
|
|
321
|
+
</Card>
|
|
322
|
+
<Card variant="stat">
|
|
323
|
+
<CardContent>
|
|
324
|
+
<CardStat
|
|
325
|
+
value="2.4M"
|
|
326
|
+
label="Public Servants"
|
|
327
|
+
change="-1.2%"
|
|
328
|
+
changeDirection="down"
|
|
329
|
+
/>
|
|
330
|
+
</CardContent>
|
|
331
|
+
</Card>
|
|
332
|
+
<Card variant="stat">
|
|
333
|
+
<CardContent>
|
|
334
|
+
<CardStat
|
|
335
|
+
value="14"
|
|
336
|
+
label="Provinces & Territories"
|
|
337
|
+
changeDirection="neutral"
|
|
338
|
+
/>
|
|
339
|
+
</CardContent>
|
|
340
|
+
</Card>
|
|
341
|
+
</div>
|
|
342
|
+
),
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export const ProjectCardsGrid: Story = {
|
|
346
|
+
render: () => (
|
|
347
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))", gap: "24px" }}>
|
|
348
|
+
<Card variant="project" href="#">
|
|
349
|
+
<CardImage
|
|
350
|
+
src="https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?w=600&h=400&fit=crop"
|
|
351
|
+
alt="Infrastructure"
|
|
352
|
+
/>
|
|
353
|
+
<CardContent>
|
|
354
|
+
<CardTitle>Infrastructure Report 2024</CardTitle>
|
|
355
|
+
<CardDescription>
|
|
356
|
+
Analysis of federal infrastructure investments.
|
|
357
|
+
</CardDescription>
|
|
358
|
+
<CardMeta>March 2024</CardMeta>
|
|
359
|
+
</CardContent>
|
|
360
|
+
</Card>
|
|
361
|
+
<Card variant="project" href="#">
|
|
362
|
+
<CardImage
|
|
363
|
+
src="https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?w=600&h=400&fit=crop"
|
|
364
|
+
alt="Budget"
|
|
365
|
+
/>
|
|
366
|
+
<CardContent>
|
|
367
|
+
<CardTitle>Budget Breakdown</CardTitle>
|
|
368
|
+
<CardDescription>
|
|
369
|
+
Comprehensive federal budget analysis.
|
|
370
|
+
</CardDescription>
|
|
371
|
+
<CardMeta>February 2024</CardMeta>
|
|
372
|
+
</CardContent>
|
|
373
|
+
</Card>
|
|
374
|
+
<Card variant="project" href="#">
|
|
375
|
+
<CardImage
|
|
376
|
+
src="https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=600&h=400&fit=crop"
|
|
377
|
+
alt="Healthcare"
|
|
378
|
+
/>
|
|
379
|
+
<CardContent>
|
|
380
|
+
<CardTitle>Healthcare Spending</CardTitle>
|
|
381
|
+
<CardDescription>
|
|
382
|
+
Provincial healthcare expenditure trends.
|
|
383
|
+
</CardDescription>
|
|
384
|
+
<CardMeta>January 2024</CardMeta>
|
|
385
|
+
</CardContent>
|
|
386
|
+
</Card>
|
|
387
|
+
</div>
|
|
388
|
+
),
|
|
389
|
+
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import { within, expect } from "@storybook/test"
|
|
3
|
+
|
|
4
|
+
import { Hero, HeroTitle, HeroSubtitle, HeroActions } from "./Hero"
|
|
5
|
+
import { Button } from "../../primitives/Button"
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Hero> = {
|
|
8
|
+
title: "Components/Content/Hero",
|
|
9
|
+
component: Hero,
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component: `
|
|
14
|
+
A hero section component for page headers with title, subtitle, and call-to-action buttons.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
\`\`\`tsx
|
|
19
|
+
import { Hero, HeroTitle, HeroSubtitle, HeroActions } from "@buildcanada/components"
|
|
20
|
+
import { Button } from "@buildcanada/components"
|
|
21
|
+
|
|
22
|
+
<Hero variant="home" background="linen">
|
|
23
|
+
<HeroTitle>Welcome to Build Canada</HeroTitle>
|
|
24
|
+
<HeroSubtitle>
|
|
25
|
+
Making government data accessible for all Canadians.
|
|
26
|
+
</HeroSubtitle>
|
|
27
|
+
<HeroActions>
|
|
28
|
+
<Button text="Get Started" variant="solid-auburn" />
|
|
29
|
+
<Button text="Learn More" variant="outline-charcoal" icon={null} />
|
|
30
|
+
</HeroActions>
|
|
31
|
+
</Hero>
|
|
32
|
+
\`\`\`
|
|
33
|
+
|
|
34
|
+
## Variants
|
|
35
|
+
|
|
36
|
+
- **home**: Large, impactful hero for homepages
|
|
37
|
+
- **page**: Standard page header with title and description
|
|
38
|
+
- **centered**: Center-aligned for special sections or CTAs
|
|
39
|
+
|
|
40
|
+
## Sub-components
|
|
41
|
+
|
|
42
|
+
- \`HeroTitle\`: Main heading (h1)
|
|
43
|
+
- \`HeroSubtitle\`: Supporting text
|
|
44
|
+
- \`HeroActions\`: Container for CTA buttons
|
|
45
|
+
`,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
argTypes: {
|
|
50
|
+
variant: {
|
|
51
|
+
control: "select",
|
|
52
|
+
options: ["home", "page", "centered"],
|
|
53
|
+
description: "Layout variant of the hero",
|
|
54
|
+
},
|
|
55
|
+
background: {
|
|
56
|
+
control: "select",
|
|
57
|
+
options: ["white", "linen", "charcoal"],
|
|
58
|
+
description: "Background color",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default meta
|
|
64
|
+
type Story = StoryObj<typeof Hero>
|
|
65
|
+
|
|
66
|
+
export const Default: Story = {
|
|
67
|
+
args: {
|
|
68
|
+
variant: "page",
|
|
69
|
+
background: "linen",
|
|
70
|
+
children: (
|
|
71
|
+
<>
|
|
72
|
+
<HeroTitle>Page Title</HeroTitle>
|
|
73
|
+
<HeroSubtitle>
|
|
74
|
+
A brief description of what this page is about and what
|
|
75
|
+
users can expect to find here.
|
|
76
|
+
</HeroSubtitle>
|
|
77
|
+
</>
|
|
78
|
+
),
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const HomeHero: Story = {
|
|
83
|
+
args: {
|
|
84
|
+
variant: "home",
|
|
85
|
+
background: "linen",
|
|
86
|
+
children: (
|
|
87
|
+
<>
|
|
88
|
+
<HeroTitle>Build Canada</HeroTitle>
|
|
89
|
+
<HeroSubtitle>
|
|
90
|
+
Making government data accessible and understandable for all Canadians.
|
|
91
|
+
Explore spending, analyze trends, and discover insights.
|
|
92
|
+
</HeroSubtitle>
|
|
93
|
+
<HeroActions>
|
|
94
|
+
<Button text="Explore Data" variant="solid-auburn" />
|
|
95
|
+
<Button text="Learn More" variant="outline-charcoal" icon={null} />
|
|
96
|
+
</HeroActions>
|
|
97
|
+
</>
|
|
98
|
+
),
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const PageHero: Story = {
|
|
103
|
+
args: {
|
|
104
|
+
variant: "page",
|
|
105
|
+
background: "linen",
|
|
106
|
+
children: (
|
|
107
|
+
<>
|
|
108
|
+
<HeroTitle>About Us</HeroTitle>
|
|
109
|
+
<HeroSubtitle>
|
|
110
|
+
Learn about our mission, team, and the work we do to make
|
|
111
|
+
government spending transparent.
|
|
112
|
+
</HeroSubtitle>
|
|
113
|
+
</>
|
|
114
|
+
),
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const CenteredHero: Story = {
|
|
119
|
+
args: {
|
|
120
|
+
variant: "centered",
|
|
121
|
+
background: "linen",
|
|
122
|
+
children: (
|
|
123
|
+
<>
|
|
124
|
+
<HeroTitle>Canada Spends</HeroTitle>
|
|
125
|
+
<HeroSubtitle>
|
|
126
|
+
Interactive visualizations of government spending across
|
|
127
|
+
all levels of government in Canada.
|
|
128
|
+
</HeroSubtitle>
|
|
129
|
+
<HeroActions>
|
|
130
|
+
<Button text="View Charts" variant="solid-auburn" />
|
|
131
|
+
</HeroActions>
|
|
132
|
+
</>
|
|
133
|
+
),
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const WhiteBackground: Story = {
|
|
138
|
+
args: {
|
|
139
|
+
variant: "page",
|
|
140
|
+
background: "white",
|
|
141
|
+
children: (
|
|
142
|
+
<>
|
|
143
|
+
<HeroTitle>Research & Reports</HeroTitle>
|
|
144
|
+
<HeroSubtitle>
|
|
145
|
+
In-depth analysis and reports on Canadian government policy
|
|
146
|
+
and spending patterns.
|
|
147
|
+
</HeroSubtitle>
|
|
148
|
+
</>
|
|
149
|
+
),
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export const CharcoalBackground: Story = {
|
|
154
|
+
args: {
|
|
155
|
+
variant: "centered",
|
|
156
|
+
background: "charcoal",
|
|
157
|
+
children: (
|
|
158
|
+
<>
|
|
159
|
+
<HeroTitle>Join Our Newsletter</HeroTitle>
|
|
160
|
+
<HeroSubtitle>
|
|
161
|
+
Get the latest insights and analysis delivered directly to your inbox.
|
|
162
|
+
</HeroSubtitle>
|
|
163
|
+
<HeroActions>
|
|
164
|
+
<Button text="Subscribe" variant="solid-auburn" />
|
|
165
|
+
</HeroActions>
|
|
166
|
+
</>
|
|
167
|
+
),
|
|
168
|
+
},
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export const WithMultipleActions: Story = {
|
|
172
|
+
args: {
|
|
173
|
+
variant: "home",
|
|
174
|
+
background: "linen",
|
|
175
|
+
children: (
|
|
176
|
+
<>
|
|
177
|
+
<HeroTitle>Open Government Data</HeroTitle>
|
|
178
|
+
<HeroSubtitle>
|
|
179
|
+
Access, analyze, and visualize government spending data
|
|
180
|
+
with our free and open-source tools.
|
|
181
|
+
</HeroSubtitle>
|
|
182
|
+
<HeroActions>
|
|
183
|
+
<Button text="Get Started" variant="solid-auburn" />
|
|
184
|
+
<Button text="View Demo" variant="outline-charcoal" icon={null} />
|
|
185
|
+
<Button text="Documentation" variant="outline-charcoal" icon={null} />
|
|
186
|
+
</HeroActions>
|
|
187
|
+
</>
|
|
188
|
+
),
|
|
189
|
+
},
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export const MinimalHero: Story = {
|
|
193
|
+
args: {
|
|
194
|
+
variant: "page",
|
|
195
|
+
background: "linen",
|
|
196
|
+
children: (
|
|
197
|
+
<HeroTitle>Contact</HeroTitle>
|
|
198
|
+
),
|
|
199
|
+
},
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export const LongContent: Story = {
|
|
203
|
+
args: {
|
|
204
|
+
variant: "home",
|
|
205
|
+
background: "linen",
|
|
206
|
+
children: (
|
|
207
|
+
<>
|
|
208
|
+
<HeroTitle>Understanding Government Spending in Canada</HeroTitle>
|
|
209
|
+
<HeroSubtitle>
|
|
210
|
+
Our platform provides comprehensive data visualization and analysis tools
|
|
211
|
+
that help citizens, researchers, and policymakers understand how public
|
|
212
|
+
money is spent across federal, provincial, and municipal governments.
|
|
213
|
+
From healthcare to infrastructure, education to defense, explore the
|
|
214
|
+
full picture of Canadian government finances.
|
|
215
|
+
</HeroSubtitle>
|
|
216
|
+
<HeroActions>
|
|
217
|
+
<Button text="Explore the Data" variant="solid-auburn" />
|
|
218
|
+
<Button text="Read Our Methodology" variant="outline-charcoal" icon={null} />
|
|
219
|
+
</HeroActions>
|
|
220
|
+
</>
|
|
221
|
+
),
|
|
222
|
+
},
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export const AllVariants: Story = {
|
|
226
|
+
render: () => (
|
|
227
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "0" }}>
|
|
228
|
+
<Hero variant="home" background="linen">
|
|
229
|
+
<HeroTitle>Home Variant</HeroTitle>
|
|
230
|
+
<HeroSubtitle>Large, impactful hero for homepages with prominent CTAs.</HeroSubtitle>
|
|
231
|
+
<HeroActions>
|
|
232
|
+
<Button text="Primary Action" variant="solid-auburn" />
|
|
233
|
+
<Button text="Secondary" variant="outline-charcoal" icon={null} />
|
|
234
|
+
</HeroActions>
|
|
235
|
+
</Hero>
|
|
236
|
+
<Hero variant="page" background="white">
|
|
237
|
+
<HeroTitle>Page Variant</HeroTitle>
|
|
238
|
+
<HeroSubtitle>Standard page header with title and optional description.</HeroSubtitle>
|
|
239
|
+
</Hero>
|
|
240
|
+
<Hero variant="centered" background="charcoal">
|
|
241
|
+
<HeroTitle>Centered Variant</HeroTitle>
|
|
242
|
+
<HeroSubtitle>Center-aligned content for special sections or CTAs.</HeroSubtitle>
|
|
243
|
+
<HeroActions>
|
|
244
|
+
<Button text="Take Action" variant="solid-auburn" />
|
|
245
|
+
</HeroActions>
|
|
246
|
+
</Hero>
|
|
247
|
+
</div>
|
|
248
|
+
),
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Interactive test: Title and subtitle render correctly
|
|
252
|
+
export const ContentTest: Story = {
|
|
253
|
+
args: {
|
|
254
|
+
variant: "page",
|
|
255
|
+
background: "linen",
|
|
256
|
+
children: (
|
|
257
|
+
<>
|
|
258
|
+
<HeroTitle>Test Title</HeroTitle>
|
|
259
|
+
<HeroSubtitle>Test subtitle text content.</HeroSubtitle>
|
|
260
|
+
</>
|
|
261
|
+
),
|
|
262
|
+
},
|
|
263
|
+
play: async ({ canvasElement }) => {
|
|
264
|
+
const canvas = within(canvasElement)
|
|
265
|
+
|
|
266
|
+
const title = canvas.getByText("Test Title")
|
|
267
|
+
const subtitle = canvas.getByText("Test subtitle text content.")
|
|
268
|
+
|
|
269
|
+
await expect(title).toBeInTheDocument()
|
|
270
|
+
await expect(subtitle).toBeInTheDocument()
|
|
271
|
+
},
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Interactive test: Action buttons are rendered
|
|
275
|
+
export const ActionsTest: Story = {
|
|
276
|
+
args: {
|
|
277
|
+
variant: "home",
|
|
278
|
+
background: "linen",
|
|
279
|
+
children: (
|
|
280
|
+
<>
|
|
281
|
+
<HeroTitle>Hero with Actions</HeroTitle>
|
|
282
|
+
<HeroSubtitle>Testing action buttons.</HeroSubtitle>
|
|
283
|
+
<HeroActions>
|
|
284
|
+
<Button text="Primary Button" variant="solid-auburn" />
|
|
285
|
+
<Button text="Secondary Button" variant="outline-charcoal" icon={null} />
|
|
286
|
+
</HeroActions>
|
|
287
|
+
</>
|
|
288
|
+
),
|
|
289
|
+
},
|
|
290
|
+
play: async ({ canvasElement }) => {
|
|
291
|
+
const canvas = within(canvasElement)
|
|
292
|
+
|
|
293
|
+
const primaryBtn = canvas.getByRole("button", { name: /primary button/i })
|
|
294
|
+
const secondaryBtn = canvas.getByRole("button", { name: /secondary button/i })
|
|
295
|
+
|
|
296
|
+
await expect(primaryBtn).toBeInTheDocument()
|
|
297
|
+
await expect(secondaryBtn).toBeInTheDocument()
|
|
298
|
+
},
|
|
299
|
+
}
|