@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
@@ -1,28 +1,25 @@
1
- import grantcodes from '@grantcodes/style-dictionary/grantcodes/json'
2
- import wireframe from '@grantcodes/style-dictionary/wireframe/json'
3
- import todomap from '@grantcodes/style-dictionary/todomap/json'
4
- import { LitElement, html, css } from 'lit'
5
- import '../../.storybook/components/color-group.component.js'
1
+ import grantcodes from "@grantcodes/style-dictionary/grantcodes/json";
2
+ import wireframe from "@grantcodes/style-dictionary/wireframe/json";
3
+ import todomap from "@grantcodes/style-dictionary/todomap/json";
4
+ import { LitElement, html, css } from "lit";
5
+ import "../../.storybook/components/color-group.component.js";
6
6
 
7
- const COLOR_PREFIXES = [
8
- 'g-color-',
9
- 'g-theme-color-'
10
- ]
7
+ const COLOR_PREFIXES = ["g-color-", "g-theme-color-"];
11
8
 
12
9
  // Filter function to only include keys that start with one of the color prefixes
13
10
  const filterByColorPrefixes = (tokens) => {
14
- return Object.fromEntries(
15
- Object.entries(tokens).filter(([key]) =>
16
- COLOR_PREFIXES.some(prefix => key.startsWith(prefix))
17
- )
18
- )
19
- }
11
+ return Object.fromEntries(
12
+ Object.entries(tokens).filter(([key]) =>
13
+ COLOR_PREFIXES.some((prefix) => key.startsWith(prefix)),
14
+ ),
15
+ );
16
+ };
20
17
 
21
18
  const themeColors = {
22
- grantcodes: filterByColorPrefixes(grantcodes),
23
- wireframe: filterByColorPrefixes(wireframe),
24
- todomap: filterByColorPrefixes(todomap),
25
- }
19
+ grantcodes: filterByColorPrefixes(grantcodes),
20
+ wireframe: filterByColorPrefixes(wireframe),
21
+ todomap: filterByColorPrefixes(todomap),
22
+ };
26
23
 
27
24
  // Color Palette Component
28
25
  class ColorPalette extends LitElement {
@@ -54,19 +51,20 @@ class ColorPalette extends LitElement {
54
51
  color: var(--g-theme-color-content-subtle, #666);
55
52
  font-size: 0.875rem;
56
53
  }
57
- `
54
+ `;
58
55
 
59
56
  static properties = {
60
57
  theme: { type: String },
61
- }
58
+ };
62
59
 
63
60
  constructor() {
64
61
  super();
65
- this.theme = 'grantcodes';
62
+ this.theme = "grantcodes";
66
63
  }
67
64
 
68
65
  getColorGroups() {
69
- const currentThemeColors = themeColors[this.theme] || themeColors.grantcodes;
66
+ const currentThemeColors =
67
+ themeColors[this.theme] || themeColors.grantcodes;
70
68
  const colorGroups = {
71
69
  neutral: {},
72
70
  "utility-green": {},
@@ -136,7 +134,8 @@ class ColorPalette extends LitElement {
136
134
 
137
135
  render() {
138
136
  const colorGroups = this.getColorGroups();
139
- const themeDisplay = this.theme.charAt(0).toUpperCase() + this.theme.slice(1);
137
+ const themeDisplay =
138
+ this.theme.charAt(0).toUpperCase() + this.theme.slice(1);
140
139
 
141
140
  return html`
142
141
  <div class="banner">
@@ -150,12 +149,12 @@ class ColorPalette extends LitElement {
150
149
 
151
150
  ${Object.entries(colorGroups).map(([groupKey, colors]) => {
152
151
  if (Object.keys(colors).length === 0) return null;
153
-
152
+
154
153
  const title = groupKey
155
154
  .split("-")
156
155
  .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
157
156
  .join(" ");
158
-
157
+
159
158
  return html`
160
159
  <color-group
161
160
  .title=${title}
@@ -163,10 +162,10 @@ class ColorPalette extends LitElement {
163
162
  ></color-group>
164
163
  `;
165
164
  })}
166
- `
165
+ `;
167
166
  }
168
167
  }
169
- customElements.define('color-palette', ColorPalette)
168
+ customElements.define("color-palette", ColorPalette);
170
169
 
171
170
  // This default export determines where your story goes in the story list
172
171
  const meta = {
@@ -1,5 +1,3 @@
1
- @import "../../util/index.css";
2
-
3
1
  :where(input, textarea, select) {
4
2
  display: block;
5
3
  accent-color: var(--g-theme-form-input-accent-color-default);
@@ -10,37 +8,8 @@
10
8
  background: var(--g-theme-form-color-background-default);
11
9
  color: var(--g-theme-form-color-content-default);
12
10
  padding: 0.5em 1em;
13
- transition:
14
- color 0.2s,
15
- background-color 0.2s,
16
- border-color 0.2s,
17
- outline 0.2s;
11
+ transition-property: color, background-color, border-color, outline;
18
12
  font-size: 1rem;
19
-
20
- /* Inlined focus-ring styles from mixin */
21
- outline-color: transparent;
22
- outline-offset: var(--g-theme-focus-ring-offset-default);
23
- outline-style: solid;
24
- outline-width: var(--g-theme-focus-ring-width-default);
25
- }
26
-
27
- :where(input, textarea, select):focus-visible {
28
- outline-color: var(--g-theme-focus-ring-color-default);
29
- }
30
-
31
- @media (prefers-contrast: more) {
32
- :where(input, textarea, select):focus-visible {
33
- outline-color: var(--g-theme-focus-ring-color-contrast);
34
- box-shadow: 0 0 0
35
- calc(
36
- (
37
- var(--g-theme-focus-ring-width-default) +
38
- var(--g-theme-focus-ring-offset-default)
39
- ) *
40
- 1.5
41
- )
42
- var(--g-theme-focus-ring-color-contrast-shadow);
43
- }
44
13
  }
45
14
 
46
15
  :where(input, textarea, select):not(textarea) {
@@ -68,7 +37,6 @@
68
37
  border-style: dashed;
69
38
  }
70
39
 
71
-
72
40
  :where(input, textarea, select):disabled {
73
41
  border-color: var(--g-theme-form-color-border-disabled);
74
42
  background: var(--g-theme-form-color-background-disabled);
@@ -87,7 +55,7 @@
87
55
 
88
56
  :where(input, textarea, select):where(textarea) {
89
57
  line-height: 1.5;
90
- min-height: 4.3em; /* Allows 2 rows with no scrollbar */
58
+ min-block-size: 4.3em; /* Allows 2 rows with no scrollbar */
91
59
  resize: vertical;
92
60
  }
93
61
 
@@ -126,8 +94,8 @@
126
94
  display: block;
127
95
  position: relative;
128
96
  appearance: none;
129
- width: 1.2rem;
130
- height: 1.2rem;
97
+ inline-size: 1.2rem;
98
+ block-size: 1.2rem;
131
99
  padding: 0;
132
100
  cursor: pointer;
133
101
  }
@@ -144,9 +112,9 @@
144
112
  font-size: 0.8rem;
145
113
  font-weight: bold;
146
114
  line-height: 0;
147
- left: 0;
148
- width: 100%;
149
- top: 50%;
115
+ inset-inline-start: 0;
116
+ inline-size: 100%;
117
+ inset-block-start: 50%;
150
118
  color: transparent;
151
119
  text-align: center;
152
120
  transition: color 0.2s;
@@ -171,8 +139,8 @@
171
139
  display: block;
172
140
  border-radius: 50%;
173
141
  /* PLACEHOLDER: $radio-inner-size: 70% - convert math.div(100% - $radio-inner-size, 2) */
174
- width: 70%;
175
- height: 70%;
142
+ inline-size: 70%;
143
+ block-size: 70%;
176
144
  margin: calc((100% - 70%) / 2);
177
145
  inset: 0;
178
146
  transition: background-color 0.2s;
@@ -1,3 +1,3 @@
1
1
  img {
2
- height: auto;
2
+ block-size: auto;
3
3
  }
@@ -1,3 +1,3 @@
1
- @import "../../../../style-dictionary/dist/css/grantcodes/tokens.css";
2
- @import "../../../../style-dictionary/dist/css/grantcodes/grantcodes.css";
3
- @import "../../../../style-dictionary/assets/fonts/greycliff.css";
1
+ @import "@grantcodes/style-dictionary/grantcodes/css";
2
+ @import "@grantcodes/style-dictionary/grantcodes/css/theme";
3
+ @import "@grantcodes/style-dictionary/assets/fonts/greycliff";
@@ -1,2 +1,3 @@
1
- @import "../../../../style-dictionary/dist/css/todomap/tokens.css";
2
- @import "../../../../style-dictionary/dist/css/todomap/todomap.css";
1
+ @import "@grantcodes/style-dictionary/todomap/css";
2
+ @import "@grantcodes/style-dictionary/todomap/css/theme";
3
+ @import "@grantcodes/style-dictionary/assets/fonts/quicksand";
@@ -1,2 +1,2 @@
1
- @import "../../../../style-dictionary/dist/css/wireframe/tokens.css";
2
- @import "../../../../style-dictionary/dist/css/wireframe/wireframe.css";
1
+ @import "@grantcodes/style-dictionary/wireframe/css";
2
+ @import "@grantcodes/style-dictionary/wireframe/css/theme";
@@ -1,13 +1,13 @@
1
- import grantcodes from '@grantcodes/style-dictionary/grantcodes/json'
2
- import wireframe from '@grantcodes/style-dictionary/wireframe/json'
3
- import todomap from '@grantcodes/style-dictionary/todomap/json'
4
- import { LitElement, html, css } from 'lit'
1
+ import grantcodes from "@grantcodes/style-dictionary/grantcodes/json";
2
+ import wireframe from "@grantcodes/style-dictionary/wireframe/json";
3
+ import todomap from "@grantcodes/style-dictionary/todomap/json";
4
+ import { LitElement, html, css } from "lit";
5
5
 
6
6
  const allTokens = {
7
7
  grantcodes,
8
8
  wireframe,
9
9
  todomap,
10
- }
10
+ };
11
11
 
12
12
  // Token List Component
13
13
  class TokenList extends LitElement {
@@ -96,31 +96,34 @@ class TokenList extends LitElement {
96
96
  color: var(--g-theme-color-content-subtle, #666);
97
97
  word-break: break-all;
98
98
  }
99
- `
99
+ `;
100
100
 
101
101
  static properties = {
102
102
  theme: { type: String },
103
- }
103
+ };
104
104
 
105
105
  constructor() {
106
106
  super();
107
- this.theme = 'grantcodes';
107
+ this.theme = "grantcodes";
108
108
  }
109
109
 
110
110
  formatValue(value) {
111
111
  if (value === null || value === undefined) {
112
- return String(value)
112
+ return String(value);
113
113
  }
114
- if (typeof value === 'object') {
115
- return JSON.stringify(value, null, 2)
114
+ if (typeof value === "object") {
115
+ return JSON.stringify(value, null, 2);
116
116
  }
117
- return String(value)
117
+ return String(value);
118
118
  }
119
119
 
120
120
  render() {
121
121
  const currentThemeTokens = allTokens[this.theme] || allTokens.grantcodes;
122
- const tokenEntries = Object.entries(currentThemeTokens).sort(([a], [b]) => a.localeCompare(b));
123
- const themeDisplay = this.theme.charAt(0).toUpperCase() + this.theme.slice(1);
122
+ const tokenEntries = Object.entries(currentThemeTokens).sort(([a], [b]) =>
123
+ a.localeCompare(b),
124
+ );
125
+ const themeDisplay =
126
+ this.theme.charAt(0).toUpperCase() + this.theme.slice(1);
124
127
 
125
128
  return html`
126
129
  <div class="banner">
@@ -143,21 +146,23 @@ class TokenList extends LitElement {
143
146
  </tr>
144
147
  </thead>
145
148
  <tbody>
146
- ${tokenEntries.map(([tokenName, value]) => html`
149
+ ${tokenEntries.map(
150
+ ([tokenName, value]) => html`
147
151
  <tr>
148
152
  <td class="token-name">--${tokenName}</td>
149
153
  <td class="token-value">${this.formatValue(value)}</td>
150
154
  <td style="background-color: var(--${tokenName});"></td>
151
155
  </tr>
152
- `)}
156
+ `,
157
+ )}
153
158
  </tbody>
154
159
  </table>
155
160
  </div>
156
- `
161
+ `;
157
162
  }
158
163
  }
159
164
 
160
- customElements.define('token-list', TokenList)
165
+ customElements.define("token-list", TokenList);
161
166
 
162
167
  // This default export determines where your story goes in the story list
163
168
  const meta = {
@@ -170,9 +175,9 @@ const meta = {
170
175
  },
171
176
  },
172
177
  },
173
- }
178
+ };
174
179
 
175
- export default meta
180
+ export default meta;
176
181
 
177
182
  // Main tokens story that responds to theme changes
178
183
  export const AllTokens = {
@@ -180,4 +185,4 @@ export const AllTokens = {
180
185
  const theme = context.globals?.theme || "grantcodes";
181
186
  return html`<token-list .theme=${theme}></token-list>`;
182
187
  },
183
- }
188
+ };
@@ -1,5 +1,3 @@
1
- @import "./util/index.css";
2
-
3
1
  html {
4
2
  font-family: var(--g-theme-typography-body-default-font-family);
5
3
  line-height: var(--g-theme-typography-body-default-line-height);
@@ -49,7 +47,7 @@ p {
49
47
  pre {
50
48
  font-family: var(--g-typography-font-family-system);
51
49
  line-height: 1.2;
52
- width: 100%;
50
+ inline-size: 100%;
53
51
  overflow: auto;
54
52
  border-radius: var(--g-theme-border-radius-md);
55
53
  /* PLACEHOLDER: u.shadow(0) - manual conversion needed */
@@ -0,0 +1,30 @@
1
+ :where(.focus-ring),
2
+ :where(:enabled) {
3
+ outline: 0px solid transparent;
4
+ outline-offset: var(--g-theme-focus-ring-offset-default);
5
+ transition-duration: var(--g-animation-duration-20);
6
+ transition-property: outline-color, width;
7
+ }
8
+
9
+ :where(.focus-ring):focus-visible,
10
+ :where(:enabled):focus-visible {
11
+ outline: var(--g-theme-focus-ring-width-default) solid
12
+ var(--g-theme-focus-ring-color-default);
13
+ }
14
+
15
+ @media (prefers-contrast: more) {
16
+ :where(.focus-ring):focus-visible,
17
+ :where(:enabled):focus-visible {
18
+ outline: var(--g-theme-focus-ring-width-default) solid
19
+ var(--g-theme-focus-ring-color-contrast);
20
+ box-shadow: 0 0 0
21
+ calc(
22
+ (
23
+ var(--g-theme-focus-ring-width-default) +
24
+ var(--g-theme-focus-ring-offset-default)
25
+ ) *
26
+ 1.5
27
+ )
28
+ var(--g-theme-focus-ring-color-contrast-shadow);
29
+ }
30
+ }
@@ -1,2 +1 @@
1
- @import "./mixins.css";
2
- @import "./functions.css";
1
+ @import "./focus-ring.css";
@@ -0,0 +1,34 @@
1
+ import { css } from "lit";
2
+
3
+ export const focusRingStyles = css`
4
+ .focus-ring,
5
+ :host(.focus-ring) {
6
+ outline: 0px solid transparent;
7
+ outline-offset: var(--g-theme-focus-ring-offset-default);
8
+ transition-duration: var(--g-animation-duration-20);
9
+ transition-properties: outline-color, width;
10
+ }
11
+
12
+ .focus-ring:focus-visible,
13
+ :host(.focus-ring):focus-visible {
14
+ outline: var(--g-theme-focus-ring-width-default) solid
15
+ var(--g-theme-focus-ring-color-default);
16
+ }
17
+
18
+ @media (prefers-contrast: more) {
19
+ .focus-ring:focus-visible,
20
+ :host(.focus-ring):focus-visible {
21
+ outline: var(--g-theme-focus-ring-width-default) solid
22
+ var(--g-theme-focus-ring-color-contrast);
23
+ box-shadow: 0 0 0
24
+ calc(
25
+ (
26
+ var(--g-theme-focus-ring-width-default) +
27
+ var(--g-theme-focus-ring-offset-default)
28
+ ) *
29
+ 1.5
30
+ )
31
+ var(--g-theme-focus-ring-color-contrast-shadow);
32
+ }
33
+ }
34
+ `;
package/src/main.js CHANGED
@@ -1,17 +1,26 @@
1
+ export * from "./components/accordion/index.js";
1
2
  export * from "./components/avatar/index.js";
2
3
  export * from "./components/button/index.js";
3
4
  export * from "./components/button-group/index.js";
4
5
  export * from "./components/card/index.js";
5
6
  export * from "./components/code-preview/index.js";
6
7
  export * from "./components/container/index.js";
8
+ export * from "./components/cta/index.js";
7
9
  export * from "./components/dialog/index.js";
8
10
  export * from "./components/dropzone/index.js";
11
+ export * from "./components/feature-list/index.js";
9
12
  export * from "./components/form-field/index.js";
10
13
  export * from "./components/gallery/index.js";
14
+ export * from "./components/hero/index.js";
11
15
  export * from "./components/icon/index.js";
12
16
  export * from "./components/loading/index.js";
17
+ export * from "./components/logo-cloud/index.js";
18
+ export * from "./components/media-text/index.js";
19
+ export * from "./components/newsletter/index.js";
13
20
  export * from "./components/notice/index.js";
14
21
  export * from "./components/pagination/index.js";
22
+ export * from "./components/pricing/index.js";
23
+ export * from "./components/stats/index.js";
15
24
  export * from "./components/tabs/index.js";
25
+ export * from "./components/testimonials/index.js";
16
26
  export * from "./components/tooltip/index.js";
17
-
@@ -0,0 +1,164 @@
1
+ import { html } from "lit";
2
+ import "../components/app-bar/app-bar.js";
3
+ import "../components/button/button.js";
4
+ import "../components/hero/hero.js";
5
+ import "../components/media-text/media-text.js";
6
+ import "../components/feature-list/feature-list.js";
7
+ import "../components/cta/cta.js";
8
+ import "../components/testimonials/testimonials.js";
9
+ import "../components/footer/footer.js";
10
+
11
+ const meta = {
12
+ title: "Pages/Agency",
13
+ parameters: {
14
+ layout: "fullscreen",
15
+ },
16
+ };
17
+
18
+ export default meta;
19
+
20
+ const footerContent = html`
21
+ <grantcodes-footer-column>
22
+ <h3>Studio North</h3>
23
+ <p>A design and engineering studio building digital products that last.</p>
24
+ </grantcodes-footer-column>
25
+
26
+ <grantcodes-footer-column>
27
+ <h3>Work</h3>
28
+ <ul>
29
+ <li><a href="/work">Case Studies</a></li>
30
+ <li><a href="/services">Services</a></li>
31
+ <li><a href="/process">Our Process</a></li>
32
+ </ul>
33
+ </grantcodes-footer-column>
34
+
35
+ <grantcodes-footer-column>
36
+ <h3>Studio</h3>
37
+ <ul>
38
+ <li><a href="/about">About Us</a></li>
39
+ <li><a href="/team">Team</a></li>
40
+ <li><a href="/careers">Careers</a></li>
41
+ <li><a href="/contact">Contact</a></li>
42
+ </ul>
43
+ </grantcodes-footer-column>
44
+ `;
45
+
46
+ /**
47
+ * Agency / studio marketing page. Uses media-text blocks to walk through
48
+ * the studio's offering, with a CTA section and testimonials from clients.
49
+ */
50
+ export const Default = {
51
+ render: () => html`
52
+ <grantcodes-app-bar>
53
+ <a slot="logo" href="/" style="font-weight: 700; font-size: 1.25rem; text-decoration: none; color: inherit;">
54
+ Studio North
55
+ </a>
56
+ <div slot="nav" style="display: flex; gap: 0.5rem;">
57
+ <a href="/work">Work</a>
58
+ <a href="/services">Services</a>
59
+ <a href="/about">About</a>
60
+ </div>
61
+ <div slot="actions">
62
+ <grantcodes-button>Get in touch</grantcodes-button>
63
+ </div>
64
+ </grantcodes-app-bar>
65
+
66
+ <grantcodes-hero
67
+ title="We design and build digital products people actually want to use"
68
+ subtitle="Studio North is a small, focused team of designers and engineers. We partner with founders and product teams to turn ideas into polished, scalable software."
69
+ button="See our work"
70
+ href="/work"
71
+ size="lg"
72
+ ></grantcodes-hero>
73
+
74
+ <grantcodes-feature-list
75
+ title="What we do"
76
+ columns="3"
77
+ items=${JSON.stringify([
78
+ {
79
+ title: "Product design",
80
+ description:
81
+ "UX research, interaction design, and visual design from concept to delivery.",
82
+ icon: "pen-tool",
83
+ },
84
+ {
85
+ title: "Web development",
86
+ description:
87
+ "Fast, accessible front-ends built with modern tooling and a focus on longevity.",
88
+ icon: "code",
89
+ },
90
+ {
91
+ title: "Brand identity",
92
+ description:
93
+ "Naming, logo, and visual language for startups that want to stand out from day one.",
94
+ icon: "layers",
95
+ },
96
+ ])}
97
+ ></grantcodes-feature-list>
98
+
99
+ <grantcodes-media-text
100
+ title="We start by understanding the problem, not the brief"
101
+ text="Before we open Figma, we spend time with your users, your data, and your team. Good design solves real problems — that only happens when we deeply understand the context. Our discovery phase isn't a box-ticking exercise; it's where the real work starts."
102
+ media=${JSON.stringify({ src: "https://placehold.co/640x480?text=Discovery+Workshop", alt: "A team working through a discovery workshop on a whiteboard", kind: "image" })}
103
+ cta=${JSON.stringify({ label: "Our process", href: "/process" })}
104
+ ></grantcodes-media-text>
105
+
106
+ <grantcodes-media-text
107
+ title="Design and engineering working side by side"
108
+ text="We don't throw designs over a wall. Our designers and engineers work in the same room (or the same Slack channel) from day one. That means fewer surprises, faster iteration, and a product that actually looks like the designs."
109
+ media=${JSON.stringify({ src: "https://placehold.co/640x480?text=Design+%26+Eng", alt: "Designers and engineers collaborating on a project", kind: "image" })}
110
+ cta=${JSON.stringify({ label: "How we work", href: "/about" })}
111
+ reverse
112
+ ></grantcodes-media-text>
113
+
114
+ <grantcodes-media-text
115
+ title="We ship, then we stick around"
116
+ text="Launch is not the finish line. We offer ongoing retainers for teams who want a trusted design and engineering partner after go-live — whether that's iterating on feedback, scaling the product, or training your internal team."
117
+ media=${JSON.stringify({ src: "https://placehold.co/640x480?text=Ongoing+Support", alt: "A chart showing continuous product iteration over time", kind: "image" })}
118
+ cta=${JSON.stringify({ label: "Engagement options", href: "/services" })}
119
+ ></grantcodes-media-text>
120
+
121
+ <grantcodes-testimonials
122
+ title="From our clients"
123
+ layout="list"
124
+ items=${JSON.stringify([
125
+ {
126
+ quote:
127
+ "Studio North turned a very messy brief into a product that exceeded what we imagined. They pushed back in the right places and delivered something genuinely special.",
128
+ name: "Leo Hartmann",
129
+ role: "Founder",
130
+ company: "Archvault",
131
+ avatar: "https://i.pravatar.cc/80?img=53",
132
+ },
133
+ {
134
+ quote:
135
+ "Their process is tight. We always knew what was happening, what was coming next, and why. That clarity is rare in agency relationships.",
136
+ name: "Chloe Bergstrom",
137
+ role: "VP Product",
138
+ company: "Meridian Health",
139
+ avatar: "https://i.pravatar.cc/80?img=25",
140
+ },
141
+ ])}
142
+ ></grantcodes-testimonials>
143
+
144
+ <grantcodes-cta
145
+ eyebrow="Let's talk"
146
+ title="Have a project in mind?"
147
+ text="We take on a small number of projects each quarter so we can give each one the attention it deserves. If you're building something meaningful, we'd love to hear about it."
148
+ primary-action=${JSON.stringify({ label: "Start a conversation", href: "/contact" })}
149
+ secondary-action=${JSON.stringify({ label: "See case studies", href: "/work" })}
150
+ align="center"
151
+ ></grantcodes-cta>
152
+
153
+ <grantcodes-footer columns="3">
154
+ ${footerContent}
155
+ <div slot="bottom">
156
+ <p>&copy; 2025 Studio North. All rights reserved.</p>
157
+ </div>
158
+ <div slot="bottom" style="display: flex; gap: var(--g-theme-spacing-md);">
159
+ <a href="/privacy">Privacy</a>
160
+ <a href="/terms">Terms</a>
161
+ </div>
162
+ </grantcodes-footer>
163
+ `,
164
+ };