@gsa-tts/graymatter-ui 0.3.0 → 0.3.2
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/README.md +33 -3
- package/assets/images/ai-icons/check-circle.svg +3 -0
- package/assets/images/ai-icons/console-icon.svg +6 -6
- package/assets/images/ai-icons/pause-button.svg +5 -0
- package/assets/images/ai-icons/play-button.svg +4 -0
- package/assets/images/api-hero-image.webp +0 -0
- package/assets/images/api-icon-w.svg +3 -0
- package/assets/images/chat-hero-image-mobile.webp +0 -0
- package/assets/images/chat-hero-image.webp +0 -0
- package/assets/images/chat-icon-b.svg +4 -0
- package/assets/images/console-hero-image.webp +0 -0
- package/assets/images/console-icon-w.svg +6 -0
- package/assets/images/og-preview.webp +0 -0
- package/assets/images/partners/gemini-government-logo.svg +129 -0
- package/assets/images/partners/microsoft-logo.svg +14 -0
- package/dist/graymatter-ui.js +1943 -1829
- package/dist/graymatter-ui.umd.cjs +37 -15
- package/package.json +6 -6
- package/src/astro-config/index.ts +10 -0
- package/src/component-options/componentOptions.ts +27 -13
- package/src/components/Button.svelte +168 -6
- package/src/components/DesktopSideNav.webcomponent.svelte +2 -0
- package/src/components/GoogleTagManager.astro +1 -1
- package/src/components/Head.astro +58 -24
- package/src/components/MobileSideMenu.svelte +2 -2
- package/src/components/MobileSideMenu.webcomponent.svelte +2 -4
- package/src/components/MobileTopNav.svelte +9 -2
- package/src/components/MobileTopNav.webcomponent.svelte +2 -2
- package/src/components/icons/ExclamationIcon.svelte +24 -0
- package/src/components/icons/index.ts +1 -0
- package/src/helpers/url.ts +13 -4
- package/src/layouts/BaseLayout.astro +2 -4
- package/src/layouts/GlobalAppLayout.astro +9 -128
- package/src/styles/base/theme.css +6 -1
- package/src/styles/base/typography.css +8 -1
- package/src/utils/getAppUrls.ts +27 -4
- package/static/uswds/styles/styles.css +1 -1
- package/static/uswds/styles/styles.css.map +1 -1
- package/assets/images/api-hero-image.png +0 -0
- package/assets/images/chat-hero-image.png +0 -0
- package/assets/images/console-hero-image.png +0 -0
- package/assets/images/lp-bg-hero-1024.webp +0 -0
- package/assets/images/lp-bg-hero-1920.webp +0 -0
- package/assets/images/lp-bg-hero-640.webp +0 -0
- package/assets/images/lp-bg-hero.png +0 -0
- /package/assets/images/{api-icon.svg → api-icon-b.svg} +0 -0
- /package/assets/images/{chat-icon.svg → chat-icon-w.svg} +0 -0
- /package/assets/images/{console-icon.svg → console-icon-b.svg} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gsa-tts/graymatter-ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -44,7 +44,6 @@
|
|
|
44
44
|
"@testing-library/jest-dom": "^6.6.3",
|
|
45
45
|
"@testing-library/svelte": "^5.2.8",
|
|
46
46
|
"@testing-library/user-event": "^14.6.1",
|
|
47
|
-
"@turbo/gen": "^2.4.0",
|
|
48
47
|
"@types/node": "^22.13.0",
|
|
49
48
|
"@uswds/compile": "1.2.2",
|
|
50
49
|
"@vitest/coverage-istanbul": "^3.0.7",
|
|
@@ -53,16 +52,17 @@
|
|
|
53
52
|
"gulp": "^5.0.0",
|
|
54
53
|
"svelte": "^5.35.4",
|
|
55
54
|
"typescript": "5.7.3",
|
|
56
|
-
"vitest": "^3.0.7",
|
|
57
55
|
"vite": "^6.3.5",
|
|
56
|
+
"vitest": "^3.0.7",
|
|
57
|
+
"@gsa-tts/graymatter-typescript-config": "0.0.1",
|
|
58
58
|
"@gsa-tts/graymatter-eslint": "0.0.1",
|
|
59
|
-
"@gsa-tts/graymatter-vitest-config": "0.0.1"
|
|
60
|
-
"@gsa-tts/graymatter-typescript-config": "0.0.1"
|
|
59
|
+
"@gsa-tts/graymatter-vitest-config": "0.0.1"
|
|
61
60
|
},
|
|
62
61
|
"dependencies": {
|
|
63
62
|
"@fontsource-variable/archivo": "^5.2.6",
|
|
63
|
+
"@fontsource/space-mono": "^5.2.8",
|
|
64
64
|
"@uswds/uswds": "3.12.0",
|
|
65
|
-
"astro": "^5.
|
|
65
|
+
"astro": "^5.12.8",
|
|
66
66
|
"slugify": "^1.6.6",
|
|
67
67
|
"@gsa-tts/graymatter-style-tokens": "0.3.0"
|
|
68
68
|
},
|
|
@@ -113,6 +113,16 @@ export function createAstroConfig({
|
|
|
113
113
|
styles: ['normal'],
|
|
114
114
|
optimizedFallbacks: true,
|
|
115
115
|
},
|
|
116
|
+
{
|
|
117
|
+
name: 'Space Mono',
|
|
118
|
+
cssVariable: '--ai-font-family-monospace', // Scoped variable name
|
|
119
|
+
provider: fontProviders.fontsource(),
|
|
120
|
+
weights: [400],
|
|
121
|
+
fallbacks: ['monospace'],
|
|
122
|
+
subsets: ['latin'],
|
|
123
|
+
styles: ['normal'],
|
|
124
|
+
optimizedFallbacks: true,
|
|
125
|
+
},
|
|
116
126
|
],
|
|
117
127
|
},
|
|
118
128
|
image: {
|
|
@@ -2,38 +2,52 @@ interface WebsiteComponentOptions {
|
|
|
2
2
|
usaBanner?: {
|
|
3
3
|
theme?: 'inverse' | 'default';
|
|
4
4
|
};
|
|
5
|
-
|
|
5
|
+
header?: {
|
|
6
6
|
theme?: 'inverse' | 'default';
|
|
7
7
|
};
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
interface
|
|
11
|
-
usaBanner?: {
|
|
12
|
-
theme?: 'inverse' | 'default';
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface ConsoleComponentOptions {
|
|
10
|
+
interface AppComponentOptions {
|
|
17
11
|
usaBanner?: {
|
|
18
12
|
theme?: 'inverse' | 'default';
|
|
19
13
|
};
|
|
20
14
|
}
|
|
21
15
|
|
|
22
16
|
export interface ComponentOptions {
|
|
17
|
+
api?: AppComponentOptions;
|
|
18
|
+
apiSubpage?: WebsiteComponentOptions;
|
|
19
|
+
chatSubpage?: WebsiteComponentOptions;
|
|
20
|
+
console?: AppComponentOptions;
|
|
21
|
+
consoleSubpage?: WebsiteComponentOptions;
|
|
22
|
+
partnershipsSubpage?: WebsiteComponentOptions;
|
|
23
23
|
website?: WebsiteComponentOptions;
|
|
24
|
-
api?: ApiComponentOptions;
|
|
25
|
-
console?: ConsoleComponentOptions;
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
export const componentOptions: ComponentOptions = {
|
|
29
|
-
|
|
27
|
+
api: {
|
|
28
|
+
usaBanner: { theme: 'default' },
|
|
29
|
+
},
|
|
30
|
+
apiSubpage: {
|
|
30
31
|
usaBanner: { theme: 'inverse' },
|
|
31
|
-
|
|
32
|
+
header: { theme: 'inverse' },
|
|
32
33
|
},
|
|
33
|
-
|
|
34
|
+
chatSubpage: {
|
|
34
35
|
usaBanner: { theme: 'default' },
|
|
36
|
+
header: { theme: 'default' },
|
|
35
37
|
},
|
|
36
38
|
console: {
|
|
37
39
|
usaBanner: { theme: 'default' },
|
|
38
40
|
},
|
|
41
|
+
consoleSubpage: {
|
|
42
|
+
usaBanner: { theme: 'inverse' },
|
|
43
|
+
header: { theme: 'inverse' },
|
|
44
|
+
},
|
|
45
|
+
partnershipsSubpage: {
|
|
46
|
+
usaBanner: { theme: 'default' },
|
|
47
|
+
header: { theme: 'default' },
|
|
48
|
+
},
|
|
49
|
+
website: {
|
|
50
|
+
usaBanner: { theme: 'inverse' },
|
|
51
|
+
header: { theme: 'inverse' },
|
|
52
|
+
},
|
|
39
53
|
};
|
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Button Component
|
|
4
|
+
*
|
|
5
|
+
* Props:
|
|
6
|
+
* - variant: 'primary' | 'secondary' | 'unstyled' (default: 'primary')
|
|
7
|
+
* - theme: 'default' | 'inverted' (default: 'default')
|
|
8
|
+
* - shape: 'round' | 'square' (default: 'round')
|
|
9
|
+
* - size: 'small' | 'medium' | 'large' (default: 'medium')
|
|
10
|
+
* - href?: string (optional - renders as <a> if provided)
|
|
11
|
+
* - disabled?: boolean (default: false)
|
|
12
|
+
* - type?: 'button' | 'submit' | 'reset' (default: 'button')
|
|
13
|
+
*
|
|
14
|
+
* Examples:
|
|
15
|
+
* - Round primary button: <Button>Click me</Button>
|
|
16
|
+
* - Square secondary button: <Button variant="secondary" shape="square">Square</Button>
|
|
17
|
+
* - Small button (any shape): <Button size="small">Small Button</Button>
|
|
18
|
+
* - Small square button: <Button variant="secondary" shape="square" size="small">Small Square</Button>
|
|
19
|
+
* - Inverted square button: <Button theme="inverted" shape="square">Inverted Square</Button>
|
|
20
|
+
*/
|
|
2
21
|
interface Props {
|
|
3
|
-
variant?: 'primary' | 'secondary';
|
|
22
|
+
variant?: 'primary' | 'secondary' | 'unstyled';
|
|
4
23
|
theme?: 'default' | 'inverted';
|
|
24
|
+
shape?: 'round' | 'square';
|
|
5
25
|
href?: string;
|
|
6
26
|
disabled?: boolean;
|
|
7
27
|
size: 'small' | 'medium' | 'large';
|
|
8
28
|
type?: 'button' | 'submit' | 'reset';
|
|
9
29
|
onclick?: (event: MouseEvent) => void;
|
|
10
|
-
children?:
|
|
30
|
+
children?: import('svelte').Snippet | null;
|
|
11
31
|
class?: string;
|
|
12
32
|
[key: `data-${string}`]: string;
|
|
13
33
|
[key: `aria-${string}`]: string;
|
|
@@ -16,7 +36,8 @@
|
|
|
16
36
|
let {
|
|
17
37
|
variant = 'primary',
|
|
18
38
|
theme = 'default',
|
|
19
|
-
|
|
39
|
+
shape = 'round',
|
|
40
|
+
href = undefined,
|
|
20
41
|
disabled = false,
|
|
21
42
|
onclick,
|
|
22
43
|
children = null,
|
|
@@ -41,6 +62,7 @@
|
|
|
41
62
|
variant === 'primary' ? 'usa-button--primary' : '',
|
|
42
63
|
variant === 'secondary' ? 'usa-button--outline ai-button--outline' : '',
|
|
43
64
|
variant === 'unstyled' ? 'ai-button--unstyled' : '',
|
|
65
|
+
shape === 'square' ? 'ai-button--square' : '',
|
|
44
66
|
]
|
|
45
67
|
.filter(Boolean)
|
|
46
68
|
.join(' ');
|
|
@@ -60,6 +82,7 @@
|
|
|
60
82
|
{/if}
|
|
61
83
|
|
|
62
84
|
<style>
|
|
85
|
+
/*! purgecss start ignore */
|
|
63
86
|
:root,
|
|
64
87
|
:host {
|
|
65
88
|
/* global button */
|
|
@@ -106,6 +129,37 @@
|
|
|
106
129
|
--ai-button-border-outline-inverted-hover: var(
|
|
107
130
|
--ai-button-border-outline-inverted-rest
|
|
108
131
|
);
|
|
132
|
+
|
|
133
|
+
/* square button specific tokens */
|
|
134
|
+
--ai-button-radius-square: var(--ai-size-4);
|
|
135
|
+
--ai-button-padding-x-square: var(--ai-size-12);
|
|
136
|
+
--ai-button-padding-y-square: var(--ai-size-6);
|
|
137
|
+
--ai-button-height-square: var(--ai-size-40);
|
|
138
|
+
--ai-button-width-square: 100%;
|
|
139
|
+
|
|
140
|
+
/* small square button tokens */
|
|
141
|
+
--ai-button-padding-x-square-small: var(--ai-size-8);
|
|
142
|
+
--ai-button-padding-y-square-small: var(--ai-size-4);
|
|
143
|
+
--ai-button-height-square-small: var(--ai-size-24);
|
|
144
|
+
|
|
145
|
+
/* square button color tokens */
|
|
146
|
+
--ai-button-background-square-primary-rest: var(--ai-color-black);
|
|
147
|
+
--ai-button-background-square-primary-hover: var(--ai-color-neutral-900);
|
|
148
|
+
--ai-button-background-square-primary-disabled: var(--ai-color-neutral-200);
|
|
149
|
+
--ai-button-text-square-primary-rest: var(--ai-color-white);
|
|
150
|
+
--ai-button-text-square-primary-hover: var(--ai-color-white);
|
|
151
|
+
--ai-button-text-square-primary-disabled: var(--ai-color-neutral-800);
|
|
152
|
+
|
|
153
|
+
--ai-button-background-square-secondary-rest: var(--ai-color-white);
|
|
154
|
+
--ai-button-background-square-secondary-hover: var(--ai-color-neutral-200);
|
|
155
|
+
--ai-button-background-square-secondary-disabled: var(
|
|
156
|
+
--ai-color-neutral-500
|
|
157
|
+
);
|
|
158
|
+
--ai-button-text-square-secondary-rest: var(--ai-color-black);
|
|
159
|
+
--ai-button-text-square-secondary-hover: var(--ai-color-black);
|
|
160
|
+
--ai-button-text-square-secondary-disabled: var(--ai-color-neutral-900);
|
|
161
|
+
--ai-button-border-square-secondary-rest: var(--ai-color-black);
|
|
162
|
+
--ai-button-border-square-secondary-hover: var(--ai-color-black);
|
|
109
163
|
}
|
|
110
164
|
|
|
111
165
|
.ai-button {
|
|
@@ -116,6 +170,11 @@
|
|
|
116
170
|
padding-inline: var(--ai-button-padding-x);
|
|
117
171
|
padding-block: var(--ai-button-padding-y);
|
|
118
172
|
margin: 0;
|
|
173
|
+
width: fit-content;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.ai-button--no-gap {
|
|
177
|
+
gap: 0;
|
|
119
178
|
}
|
|
120
179
|
|
|
121
180
|
.ai-button:is(:hover, :focus) {
|
|
@@ -169,6 +228,108 @@
|
|
|
169
228
|
border: var(--ai-button-border-inverted-hover);
|
|
170
229
|
}
|
|
171
230
|
|
|
231
|
+
/* Square button styles */
|
|
232
|
+
.ai-button--square {
|
|
233
|
+
border-radius: var(--ai-button-radius-square);
|
|
234
|
+
padding-inline: var(--ai-button-padding-x-square);
|
|
235
|
+
padding-block: var(--ai-button-padding-y-square);
|
|
236
|
+
height: var(--ai-button-height-square);
|
|
237
|
+
width: var(--ai-button-width-square);
|
|
238
|
+
width: 100%;
|
|
239
|
+
display: flex;
|
|
240
|
+
align-items: center;
|
|
241
|
+
justify-content: center;
|
|
242
|
+
border: 0.0625rem solid var(--ai-color-neutral-300);
|
|
243
|
+
box-shadow: 0 0.0625rem var(--ai-size-2) 0 rgba(0, 0, 0, 0.1);
|
|
244
|
+
transition: all var(--ai-transition-ease-fast);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* Small square button specific adjustments */
|
|
248
|
+
.ai-button--small.ai-button--square {
|
|
249
|
+
padding-inline: var(--ai-button-padding-x-square-small);
|
|
250
|
+
padding-block: var(--ai-button-padding-y-square-small);
|
|
251
|
+
height: var(--ai-button-height-square-small);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.ai-button--square:is(:hover, :focus) {
|
|
255
|
+
border-color: var(--ai-color-neutral-400);
|
|
256
|
+
box-shadow: 0 var(--ai-size-2) var(--ai-size-4) 0 rgba(0, 0, 0, 0.3);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.ai-button--square:focus {
|
|
260
|
+
outline-offset: var(--ai-size-2);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* Square button variants */
|
|
264
|
+
.ai-button--square.ai-button--primary {
|
|
265
|
+
background-color: var(--ai-button-background-square-primary-rest);
|
|
266
|
+
color: var(--ai-button-text-square-primary-rest);
|
|
267
|
+
border-color: transparent;
|
|
268
|
+
box-shadow: none;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.ai-button--square.ai-button--primary:is(:hover, :focus) {
|
|
272
|
+
background-color: var(--ai-button-background-square-primary-hover);
|
|
273
|
+
color: var(--ai-button-text-square-primary-hover);
|
|
274
|
+
border-color: transparent;
|
|
275
|
+
box-shadow: none;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.ai-button--square.ai-button--secondary {
|
|
279
|
+
background-color: var(--ai-button-background-square-secondary-rest);
|
|
280
|
+
color: var(--ai-button-text-square-secondary-rest);
|
|
281
|
+
border-color: var(--ai-button-border-square-secondary-rest);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.ai-button--square.ai-button--secondary:is(:hover, :focus) {
|
|
285
|
+
background-color: var(--ai-button-background-square-secondary-hover);
|
|
286
|
+
color: var(--ai-button-text-square-secondary-hover);
|
|
287
|
+
border-color: var(--ai-button-border-square-secondary-hover);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.ai-button--square.ai-button--outline {
|
|
291
|
+
background-color: var(--ai-color-white);
|
|
292
|
+
color: var(--ai-color-neutral-800);
|
|
293
|
+
border-color: var(--ai-color-neutral-300);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.ai-button--square.ai-button--outline:is(:hover, :focus) {
|
|
297
|
+
background-color: var(--ai-color-neutral-50);
|
|
298
|
+
color: var(--ai-color-black);
|
|
299
|
+
border-color: var(--ai-color-neutral-400);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* Square button inverted themes */
|
|
303
|
+
.ai-button--square.ai-button--inverted {
|
|
304
|
+
background-color: var(--ai-button-background-inverted-rest);
|
|
305
|
+
color: var(--ai-button-text-inverted-rest);
|
|
306
|
+
border-color: transparent;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.ai-button--square.ai-button--inverted:is(:hover, :focus) {
|
|
310
|
+
background-color: var(--ai-button-background-inverted-hover);
|
|
311
|
+
color: var(--ai-button-text-inverted-hover);
|
|
312
|
+
border-color: transparent;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.ai-button--square.ai-button--outline-inverted {
|
|
316
|
+
background-color: transparent;
|
|
317
|
+
color: var(--ai-color-white);
|
|
318
|
+
border-color: var(--ai-color-neutral-300);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.ai-button--square.ai-button--outline-inverted:is(:hover, :focus) {
|
|
322
|
+
background-color: var(--ai-color-neutral-900);
|
|
323
|
+
color: var(--ai-color-white);
|
|
324
|
+
border-color: var(--ai-color-neutral-400);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.ai-menu-buttons {
|
|
328
|
+
display: flex;
|
|
329
|
+
gap: var(--ai-size-16);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/* Unstyled button styles */
|
|
172
333
|
.ai-button--unstyled {
|
|
173
334
|
background: none;
|
|
174
335
|
color: inherit;
|
|
@@ -189,9 +350,9 @@
|
|
|
189
350
|
text-decoration: underline;
|
|
190
351
|
}
|
|
191
352
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
353
|
+
/* Unstyled square button - just center the text, reuse existing unstyled styles */
|
|
354
|
+
.ai-button--unstyled.ai-button--square {
|
|
355
|
+
text-align: center;
|
|
195
356
|
}
|
|
196
357
|
|
|
197
358
|
/* disabled button styles */
|
|
@@ -226,4 +387,5 @@
|
|
|
226
387
|
color: inherit;
|
|
227
388
|
opacity: 0.75;
|
|
228
389
|
}
|
|
390
|
+
/*! purgecss end ignore */
|
|
229
391
|
</style>
|
|
@@ -10,7 +10,7 @@ if (Astro.props.gtmID) {
|
|
|
10
10
|
gtag('js', new Date());
|
|
11
11
|
gtag('config', '${Astro.props.gtmID}');
|
|
12
12
|
</script>
|
|
13
|
-
<script id="_fed_an_ua_tag" async
|
|
13
|
+
<script id="_fed_an_ua_tag" async src="https://dap.digitalgov.gov/Universal-Federated-Analytics-Min.js?agency=GSA&subagency=TTS"></script>`;
|
|
14
14
|
}
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -1,55 +1,89 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
2
|
+
import { siteName } from '../constants';
|
|
3
|
+
const { title, description, openGraphImage, gtmID } = Astro.props;
|
|
3
4
|
import { Font } from 'astro:assets';
|
|
4
5
|
import { getUrlFromBase } from '@gsa-tts/graymatter-ui/helpers';
|
|
6
|
+
import GoogleTagManager from './GoogleTagManager.astro';
|
|
7
|
+
|
|
8
|
+
// Default values for Open Graph
|
|
9
|
+
const defaultDescription =
|
|
10
|
+
'Accelerating trusted AI adoption across government. Three powerful AI tools. Industry-leading models. One integrated platform.';
|
|
11
|
+
const defaultOgImage = getUrlFromBase('/common/assets/images/og-preview.webp');
|
|
12
|
+
|
|
13
|
+
const pageTitle = `${title} | USAi`;
|
|
14
|
+
const ogTitle = title || siteName;
|
|
15
|
+
const ogDescription = description || defaultDescription;
|
|
16
|
+
const ogImage = openGraphImage || defaultOgImage;
|
|
17
|
+
const siteUrl = Astro.site || Astro.url.origin;
|
|
18
|
+
const canonicalUrl = new URL(Astro.url.pathname, siteUrl).href;
|
|
5
19
|
---
|
|
6
20
|
|
|
7
21
|
<meta name="viewport" content="width=device-width" />
|
|
22
|
+
<title>{pageTitle}</title>
|
|
23
|
+
<script is:inline>
|
|
24
|
+
if ('performance' in window) {
|
|
25
|
+
performance.mark('usai:documenthead:start');
|
|
26
|
+
}
|
|
27
|
+
</script>
|
|
28
|
+
{gtmID && <GoogleTagManager {gtmID} />}
|
|
29
|
+
<script is:inline src=`${getUrlFromBase('uswds/js/uswds-init.min.js')}`
|
|
30
|
+
></script>
|
|
31
|
+
<Font cssVariable="--ai-font-family-sans" preload />
|
|
32
|
+
<Font cssVariable="--ai-font-family-monospace" />
|
|
33
|
+
<style>
|
|
34
|
+
body {
|
|
35
|
+
font-family: var(--ai-font-family-sans);
|
|
36
|
+
}
|
|
37
|
+
</style>
|
|
38
|
+
<script>
|
|
39
|
+
import '../../static/uswds/js/uswds.js';
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<!-- Open Graph -->
|
|
43
|
+
<meta property="og:type" content="website" />
|
|
44
|
+
<meta property="og:url" content={canonicalUrl} />
|
|
45
|
+
<meta property="og:title" content={ogTitle} />
|
|
46
|
+
<meta property="og:description" content={ogDescription} />
|
|
47
|
+
<meta property="og:image" content={ogImage} />
|
|
48
|
+
<meta property="og:site_name" content={ogTitle} />
|
|
49
|
+
|
|
50
|
+
<meta property="twitter:card" content="summary_large_image" />
|
|
51
|
+
<meta property="twitter:url" content={canonicalUrl} />
|
|
52
|
+
<meta property="twitter:title" content={ogTitle} />
|
|
53
|
+
<meta property="twitter:description" content={ogDescription} />
|
|
54
|
+
<meta property="twitter:image" content={ogImage} />
|
|
55
|
+
|
|
56
|
+
<!-- Additional meta tags -->
|
|
57
|
+
<meta name="description" content={ogDescription} />
|
|
58
|
+
<link rel="canonical" href={canonicalUrl} />
|
|
59
|
+
|
|
8
60
|
<link
|
|
9
61
|
rel="icon"
|
|
10
62
|
sizes="any"
|
|
11
|
-
href=`${getUrlFromBase('/assets/images/favicon
|
|
63
|
+
href=`${getUrlFromBase('/common/assets/images/favicon.ico')}`
|
|
12
64
|
media="(prefers-color-scheme: light)"
|
|
13
65
|
/>
|
|
14
66
|
<link
|
|
15
67
|
rel="icon"
|
|
16
68
|
type="image/svg+xml"
|
|
17
|
-
href=`${getUrlFromBase('/assets/images/favicon-light.svg')}`
|
|
69
|
+
href=`${getUrlFromBase('/common/assets/images/favicon-light.svg')}`
|
|
18
70
|
media="(prefers-color-scheme: light)"
|
|
19
71
|
/>
|
|
20
72
|
<link
|
|
21
73
|
rel="icon"
|
|
22
74
|
sizes="any"
|
|
23
|
-
href=`${getUrlFromBase('/assets/images/favicon-dark.ico')}`
|
|
75
|
+
href=`${getUrlFromBase('/common/assets/images/favicon-dark.ico')}`
|
|
24
76
|
media="(prefers-color-scheme: dark)"
|
|
25
77
|
/>
|
|
26
78
|
<link
|
|
27
79
|
rel="icon"
|
|
28
80
|
type="image/svg+xml"
|
|
29
|
-
href=`${getUrlFromBase('/assets/images/favicon-dark.svg')}`
|
|
81
|
+
href=`${getUrlFromBase('/common/assets/images/favicon-dark.svg')}`
|
|
30
82
|
media="(prefers-color-scheme: dark)"
|
|
31
83
|
/>
|
|
32
|
-
<meta name="generator" content={Astro.generator} />
|
|
33
|
-
<title>{title}</title>
|
|
34
|
-
<script is:inline>
|
|
35
|
-
if ('performance' in window) {
|
|
36
|
-
performance.mark('gsa:documenthead:start');
|
|
37
|
-
}
|
|
38
|
-
</script>
|
|
39
|
-
<script is:inline src=`${getUrlFromBase('uswds/js/uswds-init.min.js')}`
|
|
40
|
-
></script>
|
|
41
|
-
<Font cssVariable="--ai-font-family-sans" preload />
|
|
42
|
-
<style>
|
|
43
|
-
body {
|
|
44
|
-
font-family: var(--ai-font-family-sans);
|
|
45
|
-
}
|
|
46
|
-
</style>
|
|
47
|
-
<script>
|
|
48
|
-
import '../../static/uswds/js/uswds.js';
|
|
49
|
-
</script>
|
|
50
84
|
<!-- This belongs at the very bottom of the head -->
|
|
51
85
|
<script is:inline>
|
|
52
86
|
if ('performance' in window) {
|
|
53
|
-
performance.mark('
|
|
87
|
+
performance.mark('usai:documenthead:end');
|
|
54
88
|
}
|
|
55
89
|
</script>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
let sideMenuElement: HTMLDivElement;
|
|
12
12
|
let pendingMobileHash: string | null = null;
|
|
13
13
|
|
|
14
|
-
let { logoLinkUrl, logoLinkLabel } = $props();
|
|
14
|
+
let { logoLinkUrl, logoLinkLabel, children } = $props();
|
|
15
15
|
|
|
16
16
|
function handleMobileAnchorNavigate(event: Event) {
|
|
17
17
|
const customEvent = event as CustomEvent;
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
<!-- Show submenu items if available and not on discover -->
|
|
181
181
|
{#if $selectedItem && $selectedItem !== 'discover'}
|
|
182
182
|
<div class="subnav-section" part="subnav-section">
|
|
183
|
-
|
|
183
|
+
{@render children?.()}
|
|
184
184
|
</div>
|
|
185
185
|
{:else}
|
|
186
186
|
<!-- Show message when no submenu is available -->
|
|
@@ -7,9 +7,7 @@
|
|
|
7
7
|
<script lang="ts">
|
|
8
8
|
import MobileSideMenu from './MobileSideMenu.svelte';
|
|
9
9
|
|
|
10
|
-
let { logoLinkUrl, logoLinkLabel } = $props();
|
|
10
|
+
let { logoLinkUrl, logoLinkLabel, children } = $props();
|
|
11
11
|
</script>
|
|
12
12
|
|
|
13
|
-
<MobileSideMenu {logoLinkUrl} {logoLinkLabel}
|
|
14
|
-
<slot />
|
|
15
|
-
</MobileSideMenu>
|
|
13
|
+
<MobileSideMenu {logoLinkUrl} {logoLinkLabel} {children} />
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import MenuIcon from './icons/MenuIcon.svelte';
|
|
9
9
|
import { onMount } from 'svelte';
|
|
10
10
|
|
|
11
|
-
let { profileMenuData } = $props();
|
|
11
|
+
let { profileMenuData, logoLinkUrl, logoLinkLabel } = $props();
|
|
12
12
|
|
|
13
13
|
import ProfileMenu from './ProfileMenu.svelte';
|
|
14
14
|
|
|
@@ -90,7 +90,14 @@
|
|
|
90
90
|
</button>
|
|
91
91
|
|
|
92
92
|
<div class="brand">
|
|
93
|
-
|
|
93
|
+
{#if logoLinkUrl}
|
|
94
|
+
<a class="display-flex" href={logoLinkUrl} aria-label={logoLinkLabel}>
|
|
95
|
+
<Logo width={75} height={22} />
|
|
96
|
+
</a>
|
|
97
|
+
{:else}
|
|
98
|
+
<Logo width={75} height={22} />
|
|
99
|
+
{/if}
|
|
100
|
+
|
|
94
101
|
<span class="brand-text">{$selectedSubNavItemTitle || ''}</span>
|
|
95
102
|
</div>
|
|
96
103
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import MobileTopNav from './MobileTopNav.svelte';
|
|
9
9
|
|
|
10
10
|
// Props for the web component
|
|
11
|
-
let { profileMenuData } = $props();
|
|
11
|
+
let { profileMenuData, logoLinkUrl, logoLinkLabel } = $props();
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
|
-
<MobileTopNav {profileMenuData} />
|
|
14
|
+
<MobileTopNav {profileMenuData} {logoLinkUrl} {logoLinkLabel} />
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
class?: string;
|
|
4
|
+
size?: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let { class: className = '', size = 32 }: Props = $props();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<svg
|
|
11
|
+
class={className}
|
|
12
|
+
width={size}
|
|
13
|
+
height={size}
|
|
14
|
+
viewBox="0 0 32 33"
|
|
15
|
+
fill="none"
|
|
16
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
17
|
+
>
|
|
18
|
+
<path
|
|
19
|
+
fill-rule="evenodd"
|
|
20
|
+
clip-rule="evenodd"
|
|
21
|
+
d="M3 16.5028C3 9.32311 8.8203 3.50281 16 3.50281C23.1797 3.50281 29 9.32311 29 16.5028C29 23.6825 23.1797 29.5028 16 29.5028C8.8203 29.5028 3 23.6825 3 16.5028ZM16 11.5028C16.5523 11.5028 17 11.9505 17 12.5028V17.5028C17 18.0551 16.5523 18.5028 16 18.5028C15.4477 18.5028 15 18.0551 15 17.5028V12.5028C15 11.9505 15.4477 11.5028 16 11.5028ZM16 22.5028C16.5523 22.5028 17 22.0551 17 21.5028C17 20.9505 16.5523 20.5028 16 20.5028C15.4477 20.5028 15 20.9505 15 21.5028C15 22.0551 15.4477 22.5028 16 22.5028Z"
|
|
22
|
+
fill="currentColor"
|
|
23
|
+
/>
|
|
24
|
+
</svg>
|
|
@@ -4,3 +4,4 @@ export { default as ConsoleIcon } from './ConsoleIcon.svelte';
|
|
|
4
4
|
export { default as ApiIcon } from './ApiIcon.svelte';
|
|
5
5
|
export { default as MenuIcon } from './MenuIcon.svelte';
|
|
6
6
|
export { default as CloseIcon } from './CloseIcon.svelte';
|
|
7
|
+
export { default as ExclamationIcon } from './ExclamationIcon.svelte';
|
package/src/helpers/url.ts
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { normalizeTrailingSlash } from './string-formatters.js';
|
|
2
2
|
|
|
3
3
|
export const getBaseUrl = () => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (!BASEURL) {
|
|
4
|
+
// Check if we're in a browser environment
|
|
5
|
+
if (typeof window !== 'undefined') {
|
|
7
6
|
return '/';
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
// Node.js environment
|
|
10
|
+
if (typeof process !== 'undefined' && process.env) {
|
|
11
|
+
const { BASEURL } = process.env;
|
|
12
|
+
if (!BASEURL) {
|
|
13
|
+
return '/';
|
|
14
|
+
}
|
|
15
|
+
return normalizeTrailingSlash(BASEURL);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Fallback
|
|
19
|
+
return '/';
|
|
11
20
|
};
|
|
12
21
|
|
|
13
22
|
export const getUrlFromBase = (assetPath?: string) => {
|
|
@@ -4,6 +4,7 @@ import Head from '../components/Head.astro';
|
|
|
4
4
|
import UsaSkipNav from '../components/UsaSkipNav.svelte';
|
|
5
5
|
import { getPageTitle } from '../helpers/meta';
|
|
6
6
|
import GoogleTagManager from '../components/GoogleTagManager.astro';
|
|
7
|
+
const { description, openGraphImage, gtmID } = Astro.props;
|
|
7
8
|
|
|
8
9
|
const title = getPageTitle(Astro);
|
|
9
10
|
---
|
|
@@ -12,10 +13,7 @@ const title = getPageTitle(Astro);
|
|
|
12
13
|
<html lang="en">
|
|
13
14
|
<head>
|
|
14
15
|
<meta charset="UTF-8" />
|
|
15
|
-
<Head
|
|
16
|
-
<slot name="analytics">
|
|
17
|
-
<GoogleTagManager gtmID={Astro.props.gtmID} />
|
|
18
|
-
</slot>
|
|
16
|
+
<Head {title} {gtmID} {openGraphImage} {description} />
|
|
19
17
|
</head>
|
|
20
18
|
<body>
|
|
21
19
|
<slot name="skip-nav">
|