@buildcanada/components 0.1.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 (48) hide show
  1. package/package.json +67 -0
  2. package/src/assets/fonts/financier-text-regular.woff2 +0 -0
  3. package/src/assets/fonts/founders-grotesk-mono-regular.woff2 +0 -0
  4. package/src/assets/fonts/soehne-kraftig.woff2 +0 -0
  5. package/src/content/Card/Card.scss +281 -0
  6. package/src/content/Card/Card.tsx +170 -0
  7. package/src/content/Card/index.ts +22 -0
  8. package/src/content/Hero/Hero.scss +150 -0
  9. package/src/content/Hero/Hero.tsx +63 -0
  10. package/src/content/Hero/index.ts +13 -0
  11. package/src/content/StatBlock/StatBlock.scss +83 -0
  12. package/src/content/StatBlock/StatBlock.tsx +52 -0
  13. package/src/content/StatBlock/index.ts +2 -0
  14. package/src/index.ts +57 -0
  15. package/src/layout/Container/Container.scss +40 -0
  16. package/src/layout/Container/Container.tsx +29 -0
  17. package/src/layout/Container/index.ts +2 -0
  18. package/src/layout/Divider/Divider.scss +117 -0
  19. package/src/layout/Divider/Divider.tsx +32 -0
  20. package/src/layout/Divider/index.ts +2 -0
  21. package/src/layout/Grid/Grid.scss +81 -0
  22. package/src/layout/Grid/Grid.tsx +75 -0
  23. package/src/layout/Grid/index.ts +2 -0
  24. package/src/layout/Section/Section.scss +74 -0
  25. package/src/layout/Section/Section.tsx +37 -0
  26. package/src/layout/Section/index.ts +2 -0
  27. package/src/layout/Stack/Stack.scss +61 -0
  28. package/src/layout/Stack/Stack.tsx +48 -0
  29. package/src/layout/Stack/index.ts +9 -0
  30. package/src/navigation/Footer/Footer.scss +233 -0
  31. package/src/navigation/Footer/Footer.tsx +174 -0
  32. package/src/navigation/Footer/index.ts +2 -0
  33. package/src/navigation/Header/Header.scss +325 -0
  34. package/src/navigation/Header/Header.tsx +185 -0
  35. package/src/navigation/Header/index.ts +2 -0
  36. package/src/primitives/Button/Button.scss +218 -0
  37. package/src/primitives/Button/Button.tsx +120 -0
  38. package/src/primitives/Button/index.ts +2 -0
  39. package/src/primitives/Checkbox/Checkbox.scss +114 -0
  40. package/src/primitives/Checkbox/Checkbox.tsx +75 -0
  41. package/src/primitives/Checkbox/index.ts +2 -0
  42. package/src/primitives/TextField/TextField.scss +93 -0
  43. package/src/primitives/TextField/TextField.tsx +105 -0
  44. package/src/primitives/TextField/index.ts +2 -0
  45. package/src/styles/fonts.scss +27 -0
  46. package/src/styles/main.scss +34 -0
  47. package/src/styles/tokens.scss +301 -0
  48. package/src/styles/typography.scss +232 -0
@@ -0,0 +1,325 @@
1
+ @use "../../styles/tokens" as *;
2
+ @use "../../styles/typography" as *;
3
+
4
+ /*******************************************************************************
5
+ * Header Component
6
+ ******************************************************************************/
7
+
8
+ .bc-header {
9
+ position: sticky;
10
+ top: 0;
11
+ z-index: $z-sticky;
12
+ background-color: $white;
13
+ border-bottom: 1px solid $border-muted;
14
+
15
+ /***************************************************************************
16
+ * Announcement Banner
17
+ ***************************************************************************/
18
+
19
+ &__announcement {
20
+ background-color: $charcoal;
21
+ color: $white;
22
+ text-align: center;
23
+ padding: calc($space-1 / 2) $space-2;
24
+ @include body-3;
25
+
26
+ a {
27
+ color: inherit;
28
+ text-decoration: underline;
29
+
30
+ &:hover {
31
+ text-decoration: none;
32
+ }
33
+ }
34
+
35
+ &--auburn {
36
+ background-color: $auburn;
37
+ }
38
+ }
39
+
40
+ /***************************************************************************
41
+ * Main Header Row
42
+ ***************************************************************************/
43
+
44
+ &__main {
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: space-between;
48
+ padding: $space-2 $space-3;
49
+ max-width: 1280px;
50
+ margin: 0 auto;
51
+
52
+ @include md-up {
53
+ padding: $space-2 $space-5;
54
+ }
55
+ }
56
+
57
+ /***************************************************************************
58
+ * Logo
59
+ ***************************************************************************/
60
+
61
+ &__logo {
62
+ flex-shrink: 0;
63
+
64
+ a {
65
+ display: block;
66
+ text-decoration: none;
67
+ }
68
+
69
+ img {
70
+ height: 32px;
71
+ width: auto;
72
+
73
+ @include md-up {
74
+ height: 40px;
75
+ }
76
+ }
77
+ }
78
+
79
+ /***************************************************************************
80
+ * Desktop Navigation
81
+ ***************************************************************************/
82
+
83
+ &__nav {
84
+ display: none;
85
+
86
+ @include md-up {
87
+ display: block;
88
+ }
89
+ }
90
+
91
+ &__nav-list {
92
+ display: flex;
93
+ align-items: center;
94
+ gap: $space-1;
95
+ list-style: none;
96
+ margin: 0;
97
+ padding: 0;
98
+ }
99
+
100
+ &__nav-item {
101
+ position: relative;
102
+
103
+ &--has-dropdown {
104
+ // Keep dropdown open when hovering over it
105
+ &:hover .bc-header__dropdown {
106
+ display: block;
107
+ }
108
+ }
109
+ }
110
+
111
+ &__nav-link {
112
+ @include label;
113
+ display: inline-flex;
114
+ align-items: center;
115
+ gap: calc($space-1 / 2);
116
+ padding: $space-1 $space-2;
117
+ color: $text-primary;
118
+ text-decoration: none;
119
+ background: none;
120
+ border: none;
121
+ cursor: pointer;
122
+ transition: color $transition-fast;
123
+
124
+ &:hover {
125
+ color: $auburn;
126
+ }
127
+
128
+ &--dropdown {
129
+ // Visual indicator for dropdown
130
+ }
131
+ }
132
+
133
+ &__dropdown-icon {
134
+ width: 16px;
135
+ height: 16px;
136
+ transition: transform $transition-fast;
137
+
138
+ .bc-header__nav-item:hover & {
139
+ transform: rotate(180deg);
140
+ }
141
+ }
142
+
143
+ /***************************************************************************
144
+ * Dropdown Menu
145
+ ***************************************************************************/
146
+
147
+ &__dropdown {
148
+ display: none;
149
+ position: absolute;
150
+ top: 100%;
151
+ left: 0;
152
+ min-width: 200px;
153
+ background-color: $white;
154
+ border: 1px solid $border-muted;
155
+ box-shadow: $shadow-md;
156
+ list-style: none;
157
+ margin: 0;
158
+ padding: $space-1 0;
159
+ z-index: $z-dropdown;
160
+ }
161
+
162
+ &__dropdown-link {
163
+ @include body-2;
164
+ display: block;
165
+ padding: $space-1 $space-2;
166
+ color: $text-primary;
167
+ text-decoration: none;
168
+ transition: background-color $transition-fast;
169
+
170
+ &:hover {
171
+ background-color: $linen;
172
+ color: $auburn;
173
+ }
174
+ }
175
+
176
+ /***************************************************************************
177
+ * CTA Button
178
+ ***************************************************************************/
179
+
180
+ &__cta {
181
+ @include button-text-sm;
182
+ display: none;
183
+ padding: $space-1 $space-2;
184
+ background-color: $auburn;
185
+ color: $white;
186
+ text-decoration: none;
187
+ border-radius: $radius-none;
188
+ transition: background-color $transition-fast;
189
+
190
+ &:hover {
191
+ background-color: $auburn-600;
192
+ }
193
+
194
+ @include md-up {
195
+ display: inline-block;
196
+ }
197
+ }
198
+
199
+ /***************************************************************************
200
+ * Mobile Toggle
201
+ ***************************************************************************/
202
+
203
+ &__mobile-toggle {
204
+ display: flex;
205
+ align-items: center;
206
+ justify-content: center;
207
+ width: 44px;
208
+ height: 44px;
209
+ padding: 0;
210
+ background: none;
211
+ border: none;
212
+ cursor: pointer;
213
+
214
+ @include md-up {
215
+ display: none;
216
+ }
217
+ }
218
+
219
+ &__hamburger {
220
+ position: relative;
221
+ width: 24px;
222
+ height: 2px;
223
+ background-color: $charcoal;
224
+ transition: background-color $transition-fast;
225
+
226
+ &::before,
227
+ &::after {
228
+ content: "";
229
+ position: absolute;
230
+ left: 0;
231
+ width: 100%;
232
+ height: 2px;
233
+ background-color: $charcoal;
234
+ transition: transform $transition-fast;
235
+ }
236
+
237
+ &::before {
238
+ top: -8px;
239
+ }
240
+
241
+ &::after {
242
+ bottom: -8px;
243
+ }
244
+ }
245
+
246
+ &__mobile-toggle[aria-expanded="true"] &__hamburger {
247
+ background-color: transparent;
248
+
249
+ &::before {
250
+ transform: translateY(8px) rotate(45deg);
251
+ }
252
+
253
+ &::after {
254
+ transform: translateY(-8px) rotate(-45deg);
255
+ }
256
+ }
257
+
258
+ /***************************************************************************
259
+ * Mobile Menu
260
+ ***************************************************************************/
261
+
262
+ &__mobile-menu {
263
+ display: none;
264
+ position: absolute;
265
+ top: 100%;
266
+ left: 0;
267
+ right: 0;
268
+ background-color: $white;
269
+ border-bottom: 1px solid $border-muted;
270
+ padding: $space-3;
271
+ box-shadow: $shadow-lg;
272
+
273
+ &--open {
274
+ display: block;
275
+ }
276
+
277
+ @include md-up {
278
+ display: none !important;
279
+ }
280
+ }
281
+
282
+ &__mobile-nav {
283
+ list-style: none;
284
+ margin: 0;
285
+ padding: 0;
286
+ }
287
+
288
+ &__mobile-link {
289
+ @include label;
290
+ display: block;
291
+ padding: $space-2 0;
292
+ color: $text-primary;
293
+ text-decoration: none;
294
+ border-bottom: 1px solid $border-muted;
295
+
296
+ &:hover {
297
+ color: $auburn;
298
+ }
299
+
300
+ &--sub {
301
+ @include body-2;
302
+ padding-left: $space-3;
303
+ font-weight: 400;
304
+ }
305
+ }
306
+
307
+ &__mobile-subnav {
308
+ list-style: none;
309
+ margin: 0;
310
+ padding: 0;
311
+ }
312
+
313
+ &__mobile-cta {
314
+ @include button-text-md;
315
+ display: block;
316
+ width: 100%;
317
+ margin-top: $space-3;
318
+ padding: $space-2;
319
+ background-color: $auburn;
320
+ color: $white;
321
+ text-align: center;
322
+ text-decoration: none;
323
+ border-radius: $radius-none;
324
+ }
325
+ }
@@ -0,0 +1,185 @@
1
+ import cx from "classnames"
2
+ import { useState } from "react"
3
+
4
+ export interface NavItem {
5
+ label: string
6
+ href: string
7
+ dropdown?: NavItem[]
8
+ }
9
+
10
+ export interface HeaderProps {
11
+ logo: React.ReactNode
12
+ navItems?: NavItem[]
13
+ cta?: {
14
+ label: string
15
+ href: string
16
+ }
17
+ announcement?: {
18
+ text: string
19
+ href?: string
20
+ variant?: "default" | "auburn"
21
+ }
22
+ className?: string
23
+ style?: React.CSSProperties
24
+ }
25
+
26
+ export function Header({
27
+ logo,
28
+ navItems = [],
29
+ cta,
30
+ announcement,
31
+ className,
32
+ style,
33
+ }: HeaderProps) {
34
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
35
+ const [openDropdown, setOpenDropdown] = useState<string | null>(null)
36
+
37
+ const classes = cx("bc-header", className)
38
+
39
+ return (
40
+ <header className={classes} style={style}>
41
+ {announcement && (
42
+ <div
43
+ className={cx("bc-header__announcement", {
44
+ "bc-header__announcement--auburn":
45
+ announcement.variant === "auburn",
46
+ })}
47
+ >
48
+ {announcement.href ? (
49
+ <a href={announcement.href}>{announcement.text}</a>
50
+ ) : (
51
+ <span>{announcement.text}</span>
52
+ )}
53
+ </div>
54
+ )}
55
+ <div className="bc-header__main">
56
+ <div className="bc-header__logo">{logo}</div>
57
+
58
+ <nav className="bc-header__nav" aria-label="Main navigation">
59
+ <ul className="bc-header__nav-list">
60
+ {navItems.map((item) => (
61
+ <li
62
+ key={item.label}
63
+ className={cx("bc-header__nav-item", {
64
+ "bc-header__nav-item--has-dropdown": item.dropdown,
65
+ })}
66
+ onMouseEnter={() =>
67
+ item.dropdown && setOpenDropdown(item.label)
68
+ }
69
+ onMouseLeave={() =>
70
+ item.dropdown && setOpenDropdown(null)
71
+ }
72
+ >
73
+ {item.dropdown ? (
74
+ <>
75
+ <button
76
+ className="bc-header__nav-link bc-header__nav-link--dropdown"
77
+ aria-expanded={openDropdown === item.label}
78
+ aria-haspopup="true"
79
+ >
80
+ {item.label}
81
+ <svg
82
+ className="bc-header__dropdown-icon"
83
+ viewBox="0 0 20 20"
84
+ fill="currentColor"
85
+ aria-hidden="true"
86
+ >
87
+ <path
88
+ fillRule="evenodd"
89
+ d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
90
+ clipRule="evenodd"
91
+ />
92
+ </svg>
93
+ </button>
94
+ {openDropdown === item.label && (
95
+ <ul className="bc-header__dropdown">
96
+ {item.dropdown.map((subItem) => (
97
+ <li key={subItem.label}>
98
+ <a
99
+ href={subItem.href}
100
+ className="bc-header__dropdown-link"
101
+ >
102
+ {subItem.label}
103
+ </a>
104
+ </li>
105
+ ))}
106
+ </ul>
107
+ )}
108
+ </>
109
+ ) : (
110
+ <a href={item.href} className="bc-header__nav-link">
111
+ {item.label}
112
+ </a>
113
+ )}
114
+ </li>
115
+ ))}
116
+ </ul>
117
+ </nav>
118
+
119
+ {cta && (
120
+ <a href={cta.href} className="bc-header__cta">
121
+ {cta.label}
122
+ </a>
123
+ )}
124
+
125
+ <button
126
+ className="bc-header__mobile-toggle"
127
+ onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
128
+ aria-expanded={mobileMenuOpen}
129
+ aria-label="Toggle navigation menu"
130
+ >
131
+ <span className="bc-header__hamburger" />
132
+ </button>
133
+ </div>
134
+
135
+ {/* Mobile Menu */}
136
+ <div
137
+ className={cx("bc-header__mobile-menu", {
138
+ "bc-header__mobile-menu--open": mobileMenuOpen,
139
+ })}
140
+ >
141
+ <nav aria-label="Mobile navigation">
142
+ <ul className="bc-header__mobile-nav">
143
+ {navItems.map((item) => (
144
+ <li key={item.label}>
145
+ <a
146
+ href={item.href}
147
+ className="bc-header__mobile-link"
148
+ onClick={() => setMobileMenuOpen(false)}
149
+ >
150
+ {item.label}
151
+ </a>
152
+ {item.dropdown && (
153
+ <ul className="bc-header__mobile-subnav">
154
+ {item.dropdown.map((subItem) => (
155
+ <li key={subItem.label}>
156
+ <a
157
+ href={subItem.href}
158
+ className="bc-header__mobile-link bc-header__mobile-link--sub"
159
+ onClick={() => setMobileMenuOpen(false)}
160
+ >
161
+ {subItem.label}
162
+ </a>
163
+ </li>
164
+ ))}
165
+ </ul>
166
+ )}
167
+ </li>
168
+ ))}
169
+ </ul>
170
+ {cta && (
171
+ <a
172
+ href={cta.href}
173
+ className="bc-header__mobile-cta"
174
+ onClick={() => setMobileMenuOpen(false)}
175
+ >
176
+ {cta.label}
177
+ </a>
178
+ )}
179
+ </nav>
180
+ </div>
181
+ </header>
182
+ )
183
+ }
184
+
185
+ export default Header
@@ -0,0 +1,2 @@
1
+ export { Header, type HeaderProps, type NavItem } from "./Header"
2
+ export { default } from "./Header"