@gsa-tts/graymatter-ui 0.3.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsa-tts/graymatter-ui",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -52,14 +52,15 @@
52
52
  "gulp": "^5.0.0",
53
53
  "svelte": "^5.35.4",
54
54
  "typescript": "5.7.3",
55
- "vitest": "^3.0.7",
56
55
  "vite": "^6.3.5",
57
- "@gsa-tts/graymatter-eslint": "0.0.1",
56
+ "vitest": "^3.0.7",
58
57
  "@gsa-tts/graymatter-typescript-config": "0.0.1",
58
+ "@gsa-tts/graymatter-eslint": "0.0.1",
59
59
  "@gsa-tts/graymatter-vitest-config": "0.0.1"
60
60
  },
61
61
  "dependencies": {
62
62
  "@fontsource-variable/archivo": "^5.2.6",
63
+ "@fontsource/space-mono": "^5.2.8",
63
64
  "@uswds/uswds": "3.12.0",
64
65
  "astro": "^5.12.8",
65
66
  "slugify": "^1.6.6",
@@ -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: {
@@ -173,6 +173,10 @@
173
173
  width: fit-content;
174
174
  }
175
175
 
176
+ .ai-button--no-gap {
177
+ gap: 0;
178
+ }
179
+
176
180
  .ai-button:is(:hover, :focus) {
177
181
  background-color: var(--ai-button-background-primary-hover);
178
182
  color: var(--ai-button-text-primary-hover);
@@ -7,7 +7,7 @@ import GoogleTagManager from './GoogleTagManager.astro';
7
7
 
8
8
  // Default values for Open Graph
9
9
  const defaultDescription =
10
- 'Accelerating trustworthy adoption of AI across the federal government. Three powerful AI tools. Industry-leading models. One integrated platform.';
10
+ 'Accelerating trusted AI adoption across government. Three powerful AI tools. Industry-leading models. One integrated platform.';
11
11
  const defaultOgImage = getUrlFromBase('/common/assets/images/og-preview.webp');
12
12
 
13
13
  const pageTitle = `${title} | USAi`;
@@ -29,6 +29,7 @@ const canonicalUrl = new URL(Astro.url.pathname, siteUrl).href;
29
29
  <script is:inline src=`${getUrlFromBase('uswds/js/uswds-init.min.js')}`
30
30
  ></script>
31
31
  <Font cssVariable="--ai-font-family-sans" preload />
32
+ <Font cssVariable="--ai-font-family-monospace" />
32
33
  <style>
33
34
  body {
34
35
  font-family: var(--ai-font-family-sans);
@@ -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
- <slot />
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
- <Logo width={75} height={22} />
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} />
@@ -50,7 +50,12 @@ const {
50
50
 
51
51
  <!-- Mobile Navigation -->
52
52
  <nav aria-label="Mobile navigation">
53
- <MobileTopNav client:load {profileMenuData} />
53
+ <MobileTopNav
54
+ client:load
55
+ {profileMenuData}
56
+ {logoLinkUrl}
57
+ {logoLinkLabel}
58
+ />
54
59
  <MobileSideMenu client:load {logoLinkUrl} {logoLinkLabel}>
55
60
  <slot name="sub-nav" />
56
61
  </MobileSideMenu>
@@ -104,10 +109,6 @@ const {
104
109
  const mobileRect = mobileContent.getBoundingClientRect();
105
110
  const scrollTop =
106
111
  mobileContent.scrollTop + rect.top - mobileRect.top;
107
- console.log(
108
- '[GlobalAppLayout] Immediate mobile scroll to:',
109
- scrollTop
110
- );
111
112
  mobileContent.scrollTo({ top: scrollTop, behavior: 'auto' });
112
113
 
113
114
  setTimeout(() => {
@@ -140,11 +141,6 @@ const {
140
141
  if (mainContent) {
141
142
  const desktopAnchor = mainContent.querySelector(`[id="${anchor}"]`);
142
143
  if (desktopAnchor) {
143
- console.log(
144
- '[GlobalAppLayout] Immediate desktop scroll for:',
145
- anchor
146
- );
147
-
148
144
  try {
149
145
  // Add temporary scroll margin to account for header
150
146
  const originalScrollMargin =
@@ -202,27 +198,16 @@ const {
202
198
  // Check navigation flag first, before any components mount
203
199
  const isMainNavNavigation =
204
200
  sessionStorage.getItem('navigatingToMainNav') === 'true';
205
- console.log(
206
- '[GlobalAppLayout] DOMContentLoaded - navigation flag:',
207
- isMainNavNavigation
208
- );
209
201
 
210
202
  if (isMainNavNavigation) {
211
203
  // Clear the flag immediately
212
204
  sessionStorage.removeItem('navigatingToMainNav');
213
- console.log(
214
- '[GlobalAppLayout] Cleared navigation flag for main nav navigation'
215
- );
216
205
  // Don't clear header state here - let navigation components handle it
217
206
  }
218
207
 
219
208
  // Handle URL hash scrolling (fallback for cases where immediate scroll didn't work)
220
209
  if (window.location.hash) {
221
210
  const anchor = window.location.hash.substring(1);
222
- console.log(
223
- '[GlobalAppLayout] DOMContentLoaded fallback hash scroll for:',
224
- anchor
225
- );
226
211
 
227
212
  // Only proceed if we haven't already scrolled
228
213
  if (sessionStorage.getItem('globalLayoutScrolling') !== 'true') {
@@ -243,10 +228,6 @@ const {
243
228
  const mobileRect = mobileContent.getBoundingClientRect();
244
229
  const scrollTop =
245
230
  mobileContent.scrollTop + rect.top - mobileRect.top;
246
- console.log(
247
- '[GlobalAppLayout] Fallback mobile scroll to:',
248
- scrollTop
249
- );
250
231
  mobileContent.scrollTo({ top: scrollTop, behavior: 'auto' });
251
232
 
252
233
  setTimeout(() => {
@@ -287,11 +268,6 @@ const {
287
268
  );
288
269
  if (desktopAnchor) {
289
270
  setTimeout(() => {
290
- console.log(
291
- '[GlobalAppLayout] Fallback desktop scroll for:',
292
- anchor
293
- );
294
-
295
271
  // Try scrollIntoView first with a temporary offset
296
272
  try {
297
273
  // Add temporary scroll margin to account for header
@@ -305,43 +281,18 @@ const {
305
281
  inline: 'nearest',
306
282
  });
307
283
 
308
- console.log(
309
- '[GlobalAppLayout] Used fallback scrollIntoView for desktop'
310
- );
311
-
312
284
  // Restore original scroll margin after a delay
313
285
  setTimeout(() => {
314
286
  desktopAnchor.style.scrollMarginTop =
315
287
  originalScrollMargin;
316
288
  }, 1000);
317
289
  } catch (e) {
318
- console.log(
319
- '[GlobalAppLayout] Fallback scrollIntoView failed, using manual calculation:',
320
- e
321
- );
322
-
323
290
  // Fallback to manual calculation
324
291
  const headerHeight = 56;
325
292
  const rect = desktopAnchor.getBoundingClientRect();
326
293
  const scrollTop = window.scrollY + rect.top - headerHeight;
327
- console.log(
328
- '[GlobalAppLayout] Fallback desktop scroll calculation:',
329
- {
330
- anchor,
331
- rectTop: rect.top,
332
- windowScrollY: window.scrollY,
333
- headerHeight,
334
- scrollTop,
335
- elementText: desktopAnchor.textContent?.trim(),
336
- }
337
- );
338
-
339
294
  // Ensure scrollTop is not negative
340
295
  const finalScrollTop = Math.max(0, scrollTop);
341
- console.log(
342
- '[GlobalAppLayout] Fallback final scroll position:',
343
- finalScrollTop
344
- );
345
296
 
346
297
  window.scrollTo({ top: finalScrollTop, behavior: 'auto' });
347
298
  }
@@ -374,25 +325,14 @@ const {
374
325
  }, 100);
375
326
  }, 100);
376
327
  } else {
377
- console.log(
378
- '[GlobalAppLayout] Fallback desktop anchor not found in main-content container:',
379
- anchor
380
- );
381
328
  // Log all available anchors for debugging
382
329
  const allAnchors = mainContent.querySelectorAll('[id]');
383
- console.log(
384
- '[GlobalAppLayout] Available anchors in main-content:',
385
- Array.from(allAnchors).map(el => el.id)
386
- );
387
330
  // Clear the flag if anchor not found
388
331
  if (typeof window !== 'undefined') {
389
332
  sessionStorage.removeItem('globalLayoutScrolling');
390
333
  }
391
334
  }
392
335
  } else {
393
- console.log(
394
- '[GlobalAppLayout] Fallback desktop main-content container not found'
395
- );
396
336
  // Clear the flag if container not found
397
337
  if (typeof window !== 'undefined') {
398
338
  sessionStorage.removeItem('globalLayoutScrolling');
@@ -420,29 +360,10 @@ const {
420
360
  const wasMobile = lastWidth <= 640;
421
361
  const isMobile = currentWidth <= 640;
422
362
 
423
- console.log('[GlobalAppLayout] Resize detected:', {
424
- lastWidth,
425
- currentWidth,
426
- wasMobile,
427
- isMobile,
428
- changed: wasMobile !== isMobile,
429
- });
430
-
431
363
  if (wasMobile !== isMobile) {
432
- console.log(
433
- '[GlobalAppLayout] Layout changed from',
434
- wasMobile ? 'mobile' : 'desktop',
435
- 'to',
436
- isMobile ? 'mobile' : 'desktop'
437
- );
438
-
439
364
  // Handle anchor scrolling for layout changes
440
365
  if (window.location.hash) {
441
366
  const anchor = window.location.hash.substring(1);
442
- console.log(
443
- '[GlobalAppLayout] Layout change with URL hash:',
444
- anchor
445
- );
446
367
 
447
368
  // Wait for navigation state to update, then scroll
448
369
  setTimeout(() => {
@@ -460,10 +381,6 @@ const {
460
381
  const mobileRect = mobileContent.getBoundingClientRect();
461
382
  const scrollTop =
462
383
  mobileContent.scrollTop + rect.top - mobileRect.top;
463
- console.log(
464
- '[GlobalAppLayout] Scrolling mobile to anchor:',
465
- scrollTop
466
- );
467
384
  mobileContent.scrollTo({
468
385
  top: scrollTop,
469
386
  behavior: 'auto',
@@ -501,15 +418,6 @@ const {
501
418
  `[id="${anchor}"]`
502
419
  );
503
420
  if (desktopAnchor) {
504
- console.log(
505
- '[GlobalAppLayout] Desktop anchor found for layout change:',
506
- {
507
- anchor,
508
- elementText: desktopAnchor.textContent?.trim(),
509
- elementId: desktopAnchor.id,
510
- }
511
- );
512
-
513
421
  // Try scrollIntoView first with a temporary offset
514
422
  try {
515
423
  // Add temporary scroll margin to account for header
@@ -523,44 +431,20 @@ const {
523
431
  inline: 'nearest',
524
432
  });
525
433
 
526
- console.log(
527
- '[GlobalAppLayout] Used scrollIntoView for desktop layout change with scroll margin'
528
- );
529
-
530
434
  // Restore original scroll margin after a delay
531
435
  setTimeout(() => {
532
436
  desktopAnchor.style.scrollMarginTop =
533
437
  originalScrollMargin;
534
438
  }, 1000);
535
439
  } catch (e) {
536
- console.log(
537
- '[GlobalAppLayout] scrollIntoView failed for layout change, using manual calculation:',
538
- e
539
- );
540
-
541
440
  // Fallback to manual calculation
542
441
  const headerHeight = 56;
543
442
  const rect = desktopAnchor.getBoundingClientRect();
544
443
  const scrollTop =
545
444
  window.scrollY + rect.top - headerHeight;
546
- console.log(
547
- '[GlobalAppLayout] Desktop scroll calculation for layout change:',
548
- {
549
- anchor,
550
- rectTop: rect.top,
551
- windowScrollY: window.scrollY,
552
- headerHeight,
553
- scrollTop,
554
- elementText: desktopAnchor.textContent?.trim(),
555
- }
556
- );
557
445
 
558
446
  // Ensure scrollTop is not negative
559
447
  const finalScrollTop = Math.max(0, scrollTop);
560
- console.log(
561
- '[GlobalAppLayout] Final scroll position for layout change:',
562
- finalScrollTop
563
- );
564
448
 
565
449
  window.scrollTo({
566
450
  top: finalScrollTop,
@@ -603,11 +487,6 @@ const {
603
487
  detail: { isMobile },
604
488
  })
605
489
  );
606
- console.log(
607
- '[GlobalAppLayout] Dispatched layoutTransition event for',
608
- isMobile ? 'mobile' : 'desktop',
609
- 'layout'
610
- );
611
490
  }
612
491
 
613
492
  lastWidth = currentWidth;
@@ -50,7 +50,14 @@ h6,
50
50
  }
51
51
 
52
52
  pre {
53
- padding: var(--ai-size-8);
53
+ padding: var(--ai-size-16);
54
+ border-radius: var(--ai-size-4);
55
+ }
56
+
57
+ code {
58
+ font-family: var(--ai-font-family-monospace);
59
+ font-weight: var(--ai-font-weight-normal);
60
+ font-size: var(--ai-size-14);
54
61
  }
55
62
 
56
63
  a {