@grantcodes/ui 2.0.0 → 2.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 (181) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/custom-elements.json +1926 -191
  3. package/package.json +7 -6
  4. package/src/components/accordion/accordion.component.js +33 -0
  5. package/src/components/accordion/accordion.js +6 -0
  6. package/src/components/accordion/accordion.stories.js +88 -0
  7. package/src/components/accordion/accordion.styles.js +66 -0
  8. package/src/components/accordion/index.js +6 -0
  9. package/src/components/app-bar/app-bar.component.js +1 -3
  10. package/src/components/app-bar/app-bar.js +0 -2
  11. package/src/components/app-bar/app-bar.styles.js +222 -221
  12. package/src/components/app-bar/app-bar.test.js +58 -17
  13. package/src/components/app-bar/index.js +0 -2
  14. package/src/components/avatar/avatar.js +0 -12
  15. package/src/components/avatar/avatar.stories.js +0 -12
  16. package/src/components/avatar/avatar.styles.js +19 -19
  17. package/src/components/avatar/avatar.test.js +4 -4
  18. package/src/components/avatar/index.js +1 -13
  19. package/src/components/badge/badge.js +0 -2
  20. package/src/components/badge/badge.styles.js +78 -81
  21. package/src/components/badge/badge.test.js +18 -5
  22. package/src/components/badge/index.js +0 -2
  23. package/src/components/breadcrumb/breadcrumb.component.js +9 -10
  24. package/src/components/breadcrumb/breadcrumb.js +6 -4
  25. package/src/components/breadcrumb/breadcrumb.styles.js +86 -90
  26. package/src/components/breadcrumb/breadcrumb.test.js +15 -5
  27. package/src/components/breadcrumb/index.js +0 -2
  28. package/src/components/button/button.component.js +2 -2
  29. package/src/components/button/button.styles.js +58 -86
  30. package/src/components/button/button.test.js +8 -4
  31. package/src/components/button/index.js +1 -1
  32. package/src/components/button-group/button-group.test.js +0 -2
  33. package/src/components/button-group/index.js +1 -1
  34. package/src/components/card/card.component.js +40 -9
  35. package/src/components/card/card.js +3 -1
  36. package/src/components/card/card.stories.js +18 -5
  37. package/src/components/card/card.styles.js +46 -20
  38. package/src/components/card/card.test.js +0 -2
  39. package/src/components/card/index.js +1 -1
  40. package/src/components/code-preview/code-preview.component.js +9 -9
  41. package/src/components/code-preview/code-preview.js +0 -1
  42. package/src/components/code-preview/code-preview.styles.js +3 -3
  43. package/src/components/code-preview/code-preview.test.js +29 -8
  44. package/src/components/code-preview/index.js +1 -1
  45. package/src/components/container/container.component.js +1 -0
  46. package/src/components/container/container.js +0 -1
  47. package/src/components/container/container.stories.js +12 -4
  48. package/src/components/container/container.styles.js +37 -35
  49. package/src/components/container/container.test.js +0 -2
  50. package/src/components/container/index.js +1 -1
  51. package/src/components/cta/cta.component.js +108 -0
  52. package/src/components/cta/cta.js +6 -0
  53. package/src/components/cta/cta.stories.js +56 -0
  54. package/src/components/cta/cta.styles.js +64 -0
  55. package/src/components/cta/index.js +1 -0
  56. package/src/components/dialog/dialog.js +0 -1
  57. package/src/components/dialog/dialog.styles.js +8 -8
  58. package/src/components/dialog/dialog.test.js +11 -5
  59. package/src/components/dialog/index.js +1 -1
  60. package/src/components/dropdown/dropdown.component.js +5 -3
  61. package/src/components/dropdown/dropdown.js +6 -4
  62. package/src/components/dropdown/dropdown.styles.js +5 -5
  63. package/src/components/dropdown/dropdown.test.js +20 -4
  64. package/src/components/dropdown/index.js +0 -2
  65. package/src/components/dropzone/dropzone.component.js +7 -6
  66. package/src/components/dropzone/dropzone.styles.js +4 -4
  67. package/src/components/dropzone/dropzone.test.js +6 -4
  68. package/src/components/dropzone/index.js +1 -1
  69. package/src/components/feature-list/feature-list.component.js +130 -0
  70. package/src/components/feature-list/feature-list.js +6 -0
  71. package/src/components/feature-list/feature-list.stories.js +117 -0
  72. package/src/components/feature-list/feature-list.styles.js +82 -0
  73. package/src/components/feature-list/index.js +1 -0
  74. package/src/components/footer/footer-column.styles.js +46 -47
  75. package/src/components/footer/footer.js +6 -2
  76. package/src/components/footer/footer.styles.js +6 -6
  77. package/src/components/footer/footer.test.js +9 -4
  78. package/src/components/footer/index.js +1 -1
  79. package/src/components/form-field/form-field.component.js +1 -3
  80. package/src/components/form-field/form-field.js +0 -1
  81. package/src/components/form-field/form-field.styles.js +35 -37
  82. package/src/components/form-field/form-field.test.js +9 -4
  83. package/src/components/form-field/index.js +1 -1
  84. package/src/components/gallery/gallery-image.js +0 -1
  85. package/src/components/gallery/gallery.js +0 -1
  86. package/src/components/gallery/gallery.styles.js +1 -1
  87. package/src/components/gallery/gallery.test.js +5 -3
  88. package/src/components/gallery/index.js +2 -2
  89. package/src/components/hero/hero.component.js +66 -0
  90. package/src/components/hero/hero.js +6 -0
  91. package/src/components/hero/hero.stories.js +53 -0
  92. package/src/components/hero/hero.styles.js +46 -0
  93. package/src/components/hero/index.js +1 -0
  94. package/src/components/icon/icon.js +3 -2
  95. package/src/components/icon/icon.stories.js +2 -1
  96. package/src/components/icon/icon.styles.js +23 -21
  97. package/src/components/icon/icon.test.js +2 -3
  98. package/src/components/icon/index.js +1 -1
  99. package/src/components/loading/index.js +1 -1
  100. package/src/components/loading/loading.js +3 -2
  101. package/src/components/loading/loading.styles.js +1 -1
  102. package/src/components/loading/loading.test.js +0 -2
  103. package/src/components/logo-cloud/index.js +1 -0
  104. package/src/components/logo-cloud/logo-cloud.component.js +81 -0
  105. package/src/components/logo-cloud/logo-cloud.js +6 -0
  106. package/src/components/logo-cloud/logo-cloud.stories.js +107 -0
  107. package/src/components/logo-cloud/logo-cloud.styles.js +68 -0
  108. package/src/components/media-text/index.js +1 -0
  109. package/src/components/media-text/media-text.component.js +100 -0
  110. package/src/components/media-text/media-text.js +6 -0
  111. package/src/components/media-text/media-text.stories.js +69 -0
  112. package/src/components/media-text/media-text.styles.js +66 -0
  113. package/src/components/newsletter/index.js +1 -0
  114. package/src/components/newsletter/newsletter.component.js +101 -0
  115. package/src/components/newsletter/newsletter.js +6 -0
  116. package/src/components/newsletter/newsletter.stories.js +59 -0
  117. package/src/components/newsletter/newsletter.styles.js +89 -0
  118. package/src/components/notice/index.js +1 -1
  119. package/src/components/notice/notice.js +0 -1
  120. package/src/components/notice/notice.styles.js +7 -7
  121. package/src/components/notice/notice.test.js +15 -5
  122. package/src/components/pagination/index.js +1 -1
  123. package/src/components/pagination/pagination.stories.js +1 -3
  124. package/src/components/pagination/pagination.styles.js +1 -1
  125. package/src/components/pagination/pagination.test.js +9 -4
  126. package/src/components/pricing/index.js +1 -0
  127. package/src/components/pricing/pricing.component.js +119 -0
  128. package/src/components/pricing/pricing.js +6 -0
  129. package/src/components/pricing/pricing.stories.js +123 -0
  130. package/src/components/pricing/pricing.styles.js +135 -0
  131. package/src/components/sidebar/index.js +0 -2
  132. package/src/components/sidebar/sidebar.component.js +12 -10
  133. package/src/components/sidebar/sidebar.js +3 -3
  134. package/src/components/sidebar/sidebar.stories.js +0 -2
  135. package/src/components/sidebar/sidebar.styles.js +181 -186
  136. package/src/components/sidebar/sidebar.test.js +48 -13
  137. package/src/components/stats/index.js +1 -0
  138. package/src/components/stats/stats.component.js +73 -0
  139. package/src/components/stats/stats.js +6 -0
  140. package/src/components/stats/stats.stories.js +64 -0
  141. package/src/components/stats/stats.styles.js +66 -0
  142. package/src/components/tabs/index.js +2 -2
  143. package/src/components/tabs/internal/tabs-button.component.js +1 -1
  144. package/src/components/tabs/internal/tabs-button.js +0 -1
  145. package/src/components/tabs/tab.js +0 -1
  146. package/src/components/tabs/tabs.js +3 -2
  147. package/src/components/tabs/tabs.styles.js +84 -74
  148. package/src/components/testimonials/index.js +1 -0
  149. package/src/components/testimonials/testimonials.component.js +97 -0
  150. package/src/components/testimonials/testimonials.js +6 -0
  151. package/src/components/testimonials/testimonials.stories.js +78 -0
  152. package/src/components/testimonials/testimonials.styles.js +82 -0
  153. package/src/components/toast/index.js +0 -2
  154. package/src/components/toast/toast.component.js +1 -3
  155. package/src/components/toast/toast.js +10 -5
  156. package/src/components/toast/toast.stories.js +9 -5
  157. package/src/components/toast/toast.styles.js +199 -201
  158. package/src/components/toast/toast.test.js +38 -10
  159. package/src/components/tooltip/index.js +1 -1
  160. package/src/components/tooltip/tooltip.js +3 -2
  161. package/src/components/tooltip/tooltip.styles.js +3 -3
  162. package/src/components/tooltip/tooltip.test.js +10 -4
  163. package/src/css/base.css +8 -5
  164. package/src/css/colors.stories.js +27 -28
  165. package/src/css/elements/forms/input.css +9 -41
  166. package/src/css/elements/media/image.css +1 -1
  167. package/src/css/themes/grantcodes.css +3 -3
  168. package/src/css/themes/todomap.css +3 -2
  169. package/src/css/themes/wireframe.css +2 -2
  170. package/src/css/tokens.stories.js +26 -21
  171. package/src/css/typography.css +1 -3
  172. package/src/css/util/focus-ring.css +30 -0
  173. package/src/css/util/index.css +1 -2
  174. package/src/lib/styles/focus-ring.styles.js +34 -0
  175. package/src/main.js +10 -1
  176. package/src/pages/agency.stories.js +164 -0
  177. package/src/pages/blog-post.stories.js +381 -0
  178. package/src/pages/saas-landing.stories.js +307 -0
  179. package/src/test-utils/assert-helpers.js +10 -8
  180. package/src/css/util/functions.css +0 -16
  181. package/src/css/util/mixins.css +0 -63
@@ -0,0 +1,66 @@
1
+ import { css } from "lit";
2
+
3
+ export const statsStyles = css`
4
+ :host {
5
+ display: block;
6
+ }
7
+
8
+ .stats {
9
+ padding-block: var(--g-theme-spacing-3xl);
10
+ padding-inline: var(--g-theme-spacing-md);
11
+ background: var(--g-theme-color-background-subtle);
12
+ }
13
+
14
+ .stats__container {
15
+ max-width: 1200px;
16
+ margin: 0 auto;
17
+ }
18
+
19
+ .stats__title {
20
+ margin: 0 0 var(--g-theme-spacing-xl);
21
+ font-size: var(--g-theme-typography-headline-sm-font-size);
22
+ font-weight: var(--g-theme-typography-headline-sm-font-weight);
23
+ text-align: center;
24
+ color: var(--g-theme-color-content-default);
25
+ }
26
+
27
+ .stats__grid {
28
+ display: grid;
29
+ grid-template-columns: repeat(var(--columns, 4), 1fr);
30
+ gap: var(--g-theme-spacing-xl);
31
+ padding: 0;
32
+ margin: 0;
33
+ list-style: none;
34
+ text-align: center;
35
+ }
36
+
37
+ @media (max-width: 640px) {
38
+ .stats__grid {
39
+ grid-template-columns: repeat(2, 1fr);
40
+ }
41
+ }
42
+
43
+ .stats__item {
44
+ display: flex;
45
+ flex-direction: column;
46
+ gap: var(--g-theme-spacing-xs);
47
+ }
48
+
49
+ .stats__value {
50
+ font: var(--g-theme-typography-display-default);
51
+ white-space: nowrap;
52
+ line-height: 1;
53
+ color: var(--g-theme-color-content-brand, #7c3aed);
54
+ }
55
+
56
+ .stats__label {
57
+ font-size: var(--g-theme-typography-label-default-font-size);
58
+ font-weight: var(--g-theme-typography-label-default-font-weight);
59
+ color: var(--g-theme-color-content-default);
60
+ }
61
+
62
+ .stats__context {
63
+ font-size: var(--g-theme-typography-body-sm-font-size);
64
+ color: var(--g-theme-color-content-secondary);
65
+ }
66
+ `;
@@ -1,2 +1,2 @@
1
- export * from "./tabs";
2
- export * from "./tab";
1
+ export * from "./tabs.js";
2
+ export * from "./tab.js";
@@ -30,7 +30,7 @@ export class GrantCodesTabsButton extends GrantCodesTabsItem {
30
30
  aria-selected=${this.active}
31
31
  aria-controls="${this.panelId}"
32
32
  tabindex=${ifDefined(this.active ? undefined : "-1")}
33
- class="tabs__tab ${this.active ? "is-active" : ""}"
33
+ class="tabs__tab focus-ring ${this.active ? "is-active" : ""}"
34
34
  >
35
35
  <span>${this.label}</span>
36
36
  </button>
@@ -4,4 +4,3 @@ export * from "./tabs-button.component.js";
4
4
  export default GrantCodesTabsButton;
5
5
 
6
6
  customElements.define("grantcodes-tabs-button", GrantCodesTabsButton);
7
-
@@ -4,4 +4,3 @@ export * from "./tab.component.js";
4
4
  export default GrantCodesTab;
5
5
 
6
6
  customElements.define("grantcodes-tab", GrantCodesTab);
7
-
@@ -3,5 +3,6 @@ import { GrantCodesTabs } from "./tabs.component.js";
3
3
  export * from "./tabs.component.js";
4
4
  export default GrantCodesTabs;
5
5
 
6
- customElements.define("grantcodes-tabs", GrantCodesTabs);
7
-
6
+ if (!customElements.get("grantcodes-tabs")) {
7
+ customElements.define("grantcodes-tabs", GrantCodesTabs);
8
+ }
@@ -1,88 +1,98 @@
1
1
  import { css } from "lit";
2
+ import { focusRingStyles } from "../../lib/styles/focus-ring.styles.js";
2
3
 
3
4
  export const tabsStyles = css`
4
- *,
5
- *::before,
6
- *::after {
7
- box-sizing: border-box;
8
- }
5
+ ${focusRingStyles}
9
6
 
10
- .tabs {
11
- --border-width: 3px;
12
- display: block;
13
- }
7
+ *,
8
+ *::before,
9
+ *::after {
10
+ box-sizing: border-box;
11
+ }
14
12
 
15
- .tabs__tablist {
16
- overflow: auto;
17
- contain: none;
18
- }
13
+ .tabs {
14
+ --border-width: 3px;
15
+ display: block;
16
+ }
19
17
 
20
- .tabs__tablist__inner {
21
- position: relative;
22
- display: flex;
23
- flex-direction: row;
24
- flex-wrap: nowrap;
25
- width: fit-content;
26
- min-width: 100%;
27
- background-image: linear-gradient(
28
- var(--g-theme-color-border-default, var(--g-color-brand-purple-100)),
29
- var(--g-theme-color-border-default, var(--g-color-brand-purple-100))
30
- );
31
- background-size: auto var(--border-width);
32
- background-position: bottom;
33
- background-repeat: repeat-x;
34
- }
18
+ .tabs__tablist {
19
+ overflow: auto;
20
+ contain: none;
21
+ }
35
22
 
36
- .tabs__tab {
37
- padding: 0.6em 1.2em;
38
- line-height: 1;
39
- font-size: 1rem;
40
- border: none;
41
- border-block-start: var(--border-width) solid transparent;
42
- border-block-end: var(--border-width) solid var(--g-theme-color-border-default, var(--g-color-brand-purple-100));
43
- background-color: transparent;
44
- color: var(--g-theme-color-content-default);
45
- opacity: 0.7;
46
- white-space: nowrap;
47
- cursor: pointer;
48
- transition: opacity 0.2s, border-color 0.2s, background-color 0.2s;
49
- --component-focus-ring-offset: calc(var(--component-focus-ring-width) * -1);
50
- }
23
+ .tabs__tablist__inner {
24
+ position: relative;
25
+ display: flex;
26
+ flex-direction: row;
27
+ flex-wrap: nowrap;
28
+ width: fit-content;
29
+ min-width: 100%;
30
+ background-image: linear-gradient(
31
+ var(--g-theme-color-border-default, var(--g-color-brand-purple-100)),
32
+ var(--g-theme-color-border-default, var(--g-color-brand-purple-100))
33
+ );
34
+ background-size: auto var(--border-width);
35
+ background-position: bottom;
36
+ background-repeat: repeat-x;
37
+ }
51
38
 
52
- @media (min-width: 40em) {
53
- .tabs__tab {
54
- padding-inline: 1rem;
55
- }
56
- }
39
+ .tabs__tab {
40
+ padding: 0.6em 1.2em;
41
+ line-height: 1;
42
+ font-size: var(--g-theme-typography-body-default-font-size);
43
+ border: none;
44
+ border-block-start: var(--border-width) solid transparent;
45
+ border-block-end: var(--border-width) solid
46
+ var(--g-theme-color-border-default, var(--g-color-brand-purple-100));
47
+ background-color: transparent;
48
+ color: var(--g-theme-color-content-default);
49
+ opacity: 0.7;
50
+ white-space: nowrap;
51
+ cursor: pointer;
52
+ transition:
53
+ opacity 0.2s,
54
+ border-color 0.2s,
55
+ background-color 0.2s;
56
+ }
57
57
 
58
- .tabs__tab:hover,
59
- .tabs__tab:focus-visible {
60
- opacity: 1;
61
- border-block-end-color: var(--g-theme-color-border-default, var(--g-color-brand-purple-200));
62
- }
58
+ @media (min-width: 40em) {
59
+ .tabs__tab {
60
+ padding-inline: var(--g-theme-spacing-md);
61
+ }
62
+ }
63
63
 
64
- .tabs__tab.is-active {
65
- border-block-end-color: var(--g-theme-color-border-brand, var(--g-color-brand-purple-500));
66
- background-color: var(--g-theme-color-background-subtle);
67
- color: var(--g-theme-color-content-default);
68
- z-index: 1;
69
- position: relative;
70
- opacity: 1;
71
- }
64
+ .tabs__tab:hover,
65
+ .tabs__tab:focus-visible {
66
+ opacity: 1;
67
+ border-block-end-color: var(
68
+ --g-theme-color-border-default,
69
+ var(--g-color-brand-purple-200)
70
+ );
71
+ }
72
72
 
73
- .tabs__tab:focus-visible {
74
- outline: 2px solid var(--component-focus-ring-color, rgba(106, 91, 197, 0.4));
75
- outline-offset: 2px;
76
- }
73
+ .tabs__tab.is-active {
74
+ border-block-end-color: var(
75
+ --g-theme-color-border-brand,
76
+ var(--g-color-brand-purple-500)
77
+ );
78
+ background-color: var(--g-theme-color-background-subtle);
79
+ color: var(--g-theme-color-content-default);
80
+ z-index: 1;
81
+ position: relative;
82
+ opacity: 1;
83
+ }
77
84
 
78
- .tabs__panel {
79
- margin-block-start: 1rem;
80
- outline-color: var(--g-theme-color-border-brand, var(--g-color-brand-purple-500));
81
- outline-offset: 1rem;
82
- display: none;
83
- }
85
+ .tabs__panel {
86
+ margin-block-start: var(--g-theme-spacing-md);
87
+ outline-color: var(
88
+ --g-theme-color-border-brand,
89
+ var(--g-color-brand-purple-500)
90
+ );
91
+ outline-offset: 1rem;
92
+ display: none;
93
+ }
84
94
 
85
- .tabs__panel.is-active {
86
- display: block;
87
- }
95
+ .tabs__panel.is-active {
96
+ display: block;
97
+ }
88
98
  `;
@@ -0,0 +1 @@
1
+ export * from "./testimonials.js";
@@ -0,0 +1,97 @@
1
+ import { LitElement, html } from "lit";
2
+ import { testimonialsStyles } from "./testimonials.styles.js";
3
+ import "../card/card.js";
4
+ import "../avatar/avatar.js";
5
+
6
+ export class GrantCodesTestimonials extends LitElement {
7
+ static styles = [testimonialsStyles];
8
+
9
+ static properties = {
10
+ /**
11
+ * Optional section heading.
12
+ * @type {string}
13
+ */
14
+ title: { type: String },
15
+ /**
16
+ * Testimonial items as a JSON string array: `[{"quote":"...","name":"...","role":"...","company":"...","avatar":"..."}]`.
17
+ * @type {string}
18
+ */
19
+ items: { type: String },
20
+ /**
21
+ * Display layout of the testimonials.
22
+ * @type {'cards' | 'list'}
23
+ */
24
+ layout: { type: String, reflect: true },
25
+ };
26
+
27
+ constructor() {
28
+ super();
29
+ this.title = "";
30
+ this.items = "[]";
31
+ this.layout = "cards";
32
+ }
33
+
34
+ get _items() {
35
+ try {
36
+ return JSON.parse(this.items);
37
+ } catch {
38
+ return [];
39
+ }
40
+ }
41
+
42
+ render() {
43
+ const items = this._items;
44
+ return html`
45
+ <section class="testimonials">
46
+ <div class="testimonials__container">
47
+ ${
48
+ this.title
49
+ ? html`<h2 class="testimonials__title">${this.title}</h2>`
50
+ : null
51
+ }
52
+ <ul
53
+ class="testimonials__grid testimonials__grid--${this.layout}"
54
+ role="list"
55
+ >
56
+ ${items.map(
57
+ (item) => html`
58
+ <li class="testimonials__item">
59
+ <grantcodes-card>
60
+ <blockquote class="testimonials__quote" slot="header">
61
+ <p class="testimonials__text">
62
+ &ldquo;${item.quote}&rdquo;
63
+ </p>
64
+ </blockquote>
65
+ <footer class="testimonials__attribution" slot="footer">
66
+ ${
67
+ item.avatar
68
+ ? html`<grantcodes-avatar
69
+ src=${item.avatar}
70
+ name=${item.name}
71
+ size="small"
72
+ ></grantcodes-avatar>`
73
+ : null
74
+ }
75
+ <div class="testimonials__meta">
76
+ <cite class="testimonials__name">${item.name}</cite>
77
+ ${
78
+ item.role || item.company
79
+ ? html`<span class="testimonials__role">
80
+ ${[item.role, item.company]
81
+ .filter(Boolean)
82
+ .join(", ")}
83
+ </span>`
84
+ : null
85
+ }
86
+ </div>
87
+ </footer>
88
+ </grantcodes-card>
89
+ </li>
90
+ `,
91
+ )}
92
+ </ul>
93
+ </div>
94
+ </section>
95
+ `;
96
+ }
97
+ }
@@ -0,0 +1,6 @@
1
+ import { GrantCodesTestimonials } from "./testimonials.component.js";
2
+
3
+ export * from "./testimonials.component.js";
4
+ export default GrantCodesTestimonials;
5
+
6
+ customElements.define("grantcodes-testimonials", GrantCodesTestimonials);
@@ -0,0 +1,78 @@
1
+ import { getStorybookHelpers } from "@wc-toolkit/storybook-helpers";
2
+ import "./testimonials.js";
3
+
4
+ const { events, args, argTypes } = getStorybookHelpers(
5
+ "grantcodes-testimonials",
6
+ );
7
+
8
+ const meta = {
9
+ title: "Blocks/Testimonials",
10
+ component: "grantcodes-testimonials",
11
+ args,
12
+ argTypes,
13
+ parameters: {
14
+ actions: {
15
+ handles: events,
16
+ },
17
+ layout: "fullscreen",
18
+ },
19
+ };
20
+
21
+ export default meta;
22
+
23
+ const sampleItems = JSON.stringify([
24
+ {
25
+ quote:
26
+ "This component library saved us weeks of design work. The theming system is incredibly flexible.",
27
+ name: "Sarah Chen",
28
+ role: "Lead Engineer",
29
+ company: "Acme Corp",
30
+ avatar: "https://i.pravatar.cc/64?img=1",
31
+ },
32
+ {
33
+ quote: "Accessibility out of the box. Our audits pass first time now.",
34
+ name: "Marcus Webb",
35
+ role: "Frontend Developer",
36
+ company: "Globex",
37
+ avatar: "https://i.pravatar.cc/64?img=2",
38
+ },
39
+ {
40
+ quote: "The design tokens make it trivial to match our brand guidelines.",
41
+ name: "Priya Sharma",
42
+ role: "Design Systems Lead",
43
+ company: "Initech",
44
+ avatar: "https://i.pravatar.cc/64?img=3",
45
+ },
46
+ ]);
47
+
48
+ /**
49
+ * Default card layout testimonials.
50
+ */
51
+ export const Cards = {
52
+ args: {
53
+ title: "What people are saying",
54
+ items: sampleItems,
55
+ layout: "cards",
56
+ },
57
+ };
58
+
59
+ /**
60
+ * List layout — stacked testimonials with more visual prominence.
61
+ */
62
+ export const List = {
63
+ args: {
64
+ title: "Customer stories",
65
+ items: sampleItems,
66
+ layout: "list",
67
+ },
68
+ };
69
+
70
+ /**
71
+ * Testimonials without a section heading.
72
+ */
73
+ export const NoHeading = {
74
+ args: {
75
+ items: sampleItems,
76
+ layout: "cards",
77
+ },
78
+ };
@@ -0,0 +1,82 @@
1
+ import { css } from "lit";
2
+
3
+ export const testimonialsStyles = css`
4
+ :host {
5
+ display: block;
6
+ }
7
+
8
+ .testimonials {
9
+ padding-block: var(--g-theme-spacing-3xl);
10
+ padding-inline: var(--g-theme-spacing-md);
11
+ }
12
+
13
+ .testimonials__container {
14
+ max-width: 1200px;
15
+ margin: 0 auto;
16
+ }
17
+
18
+ .testimonials__title {
19
+ margin: 0 0 var(--g-theme-spacing-2xl);
20
+ font-size: var(--g-theme-typography-headline-sm-font-size);
21
+ font-weight: var(--g-theme-typography-headline-sm-font-weight);
22
+ text-align: center;
23
+ color: var(--g-theme-color-content-default);
24
+ }
25
+
26
+ .testimonials__grid--cards {
27
+ display: grid;
28
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
29
+ gap: var(--g-theme-spacing-lg);
30
+ padding: 0;
31
+ margin: 0;
32
+ list-style: none;
33
+ }
34
+
35
+ .testimonials__grid--list {
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: var(--g-theme-spacing-xl);
39
+ max-width: 65ch;
40
+ margin: 0 auto;
41
+ padding: 0;
42
+ list-style: none;
43
+ }
44
+
45
+ .testimonials__quote {
46
+ margin: 0;
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: var(--g-theme-spacing-lg);
50
+ height: 100%;
51
+ }
52
+
53
+ .testimonials__text {
54
+ margin: 0;
55
+ font: var(--g-theme-typography-body-default);
56
+ color: var(--g-theme-color-content-default);
57
+ flex: 1;
58
+ }
59
+
60
+ .testimonials__attribution {
61
+ display: flex;
62
+ align-items: center;
63
+ gap: var(--g-theme-spacing-sm);
64
+ }
65
+
66
+ .testimonials__meta {
67
+ display: flex;
68
+ flex-direction: column;
69
+ gap: var(--g-theme-spacing-xs);
70
+ }
71
+
72
+ .testimonials__name {
73
+ font: var(--g-theme-typography-label-default);
74
+ font-style: normal;
75
+ color: var(--g-theme-color-content-default);
76
+ }
77
+
78
+ .testimonials__role {
79
+ font-size: var(--g-theme-typography-body-sm-font-size);
80
+ color: var(--g-theme-color-content-secondary);
81
+ }
82
+ `;
@@ -1,3 +1 @@
1
1
  export * from "./toast.js";
2
-
3
-
@@ -117,7 +117,7 @@ export class GrantCodesToast extends LitElement {
117
117
  return html`
118
118
  <button
119
119
  type="button"
120
- class="toast__close"
120
+ class="toast__close focus-ring"
121
121
  @click=${this._handleDismiss}
122
122
  aria-label="Dismiss notification"
123
123
  >
@@ -183,5 +183,3 @@ export class GrantCodesToastContainer extends LitElement {
183
183
  `;
184
184
  }
185
185
  }
186
-
187
-
@@ -1,9 +1,14 @@
1
- import { GrantCodesToast, GrantCodesToastContainer } from "./toast.component.js";
1
+ import {
2
+ GrantCodesToast,
3
+ GrantCodesToastContainer,
4
+ } from "./toast.component.js";
2
5
 
3
6
  export * from "./toast.component.js";
4
7
  export default GrantCodesToast;
5
8
 
6
- customElements.define("grantcodes-toast", GrantCodesToast);
7
- customElements.define("grantcodes-toast-container", GrantCodesToastContainer);
8
-
9
-
9
+ if (!customElements.get("grantcodes-toast")) {
10
+ customElements.define("grantcodes-toast", GrantCodesToast);
11
+ }
12
+ if (!customElements.get("grantcodes-toast-container")) {
13
+ customElements.define("grantcodes-toast-container", GrantCodesToastContainer);
14
+ }
@@ -141,9 +141,13 @@ export const Interactive = {
141
141
  <div>
142
142
  <button
143
143
  @click=${() => {
144
- const container = document.querySelector("grantcodes-toast-container");
144
+ const container = document.querySelector(
145
+ "grantcodes-toast-container",
146
+ );
145
147
  if (!container) {
146
- const newContainer = document.createElement("grantcodes-toast-container");
148
+ const newContainer = document.createElement(
149
+ "grantcodes-toast-container",
150
+ );
147
151
  newContainer.position = "top-right";
148
152
  document.body.appendChild(newContainer);
149
153
  }
@@ -156,7 +160,9 @@ export const Interactive = {
156
160
 
157
161
  const finalContainer =
158
162
  document.querySelector("grantcodes-toast-container") ||
159
- document.body.appendChild(document.createElement("grantcodes-toast-container"));
163
+ document.body.appendChild(
164
+ document.createElement("grantcodes-toast-container"),
165
+ );
160
166
  finalContainer.appendChild(toast);
161
167
  }}
162
168
  >
@@ -165,5 +171,3 @@ export const Interactive = {
165
171
  </div>
166
172
  `,
167
173
  };
168
-
169
-