@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.
Files changed (48) hide show
  1. package/README.md +33 -3
  2. package/assets/images/ai-icons/check-circle.svg +3 -0
  3. package/assets/images/ai-icons/console-icon.svg +6 -6
  4. package/assets/images/ai-icons/pause-button.svg +5 -0
  5. package/assets/images/ai-icons/play-button.svg +4 -0
  6. package/assets/images/api-hero-image.webp +0 -0
  7. package/assets/images/api-icon-w.svg +3 -0
  8. package/assets/images/chat-hero-image-mobile.webp +0 -0
  9. package/assets/images/chat-hero-image.webp +0 -0
  10. package/assets/images/chat-icon-b.svg +4 -0
  11. package/assets/images/console-hero-image.webp +0 -0
  12. package/assets/images/console-icon-w.svg +6 -0
  13. package/assets/images/og-preview.webp +0 -0
  14. package/assets/images/partners/gemini-government-logo.svg +129 -0
  15. package/assets/images/partners/microsoft-logo.svg +14 -0
  16. package/dist/graymatter-ui.js +1943 -1829
  17. package/dist/graymatter-ui.umd.cjs +37 -15
  18. package/package.json +6 -6
  19. package/src/astro-config/index.ts +10 -0
  20. package/src/component-options/componentOptions.ts +27 -13
  21. package/src/components/Button.svelte +168 -6
  22. package/src/components/DesktopSideNav.webcomponent.svelte +2 -0
  23. package/src/components/GoogleTagManager.astro +1 -1
  24. package/src/components/Head.astro +58 -24
  25. package/src/components/MobileSideMenu.svelte +2 -2
  26. package/src/components/MobileSideMenu.webcomponent.svelte +2 -4
  27. package/src/components/MobileTopNav.svelte +9 -2
  28. package/src/components/MobileTopNav.webcomponent.svelte +2 -2
  29. package/src/components/icons/ExclamationIcon.svelte +24 -0
  30. package/src/components/icons/index.ts +1 -0
  31. package/src/helpers/url.ts +13 -4
  32. package/src/layouts/BaseLayout.astro +2 -4
  33. package/src/layouts/GlobalAppLayout.astro +9 -128
  34. package/src/styles/base/theme.css +6 -1
  35. package/src/styles/base/typography.css +8 -1
  36. package/src/utils/getAppUrls.ts +27 -4
  37. package/static/uswds/styles/styles.css +1 -1
  38. package/static/uswds/styles/styles.css.map +1 -1
  39. package/assets/images/api-hero-image.png +0 -0
  40. package/assets/images/chat-hero-image.png +0 -0
  41. package/assets/images/console-hero-image.png +0 -0
  42. package/assets/images/lp-bg-hero-1024.webp +0 -0
  43. package/assets/images/lp-bg-hero-1920.webp +0 -0
  44. package/assets/images/lp-bg-hero-640.webp +0 -0
  45. package/assets/images/lp-bg-hero.png +0 -0
  46. /package/assets/images/{api-icon.svg → api-icon-b.svg} +0 -0
  47. /package/assets/images/{chat-icon.svg → chat-icon-w.svg} +0 -0
  48. /package/assets/images/{console-icon.svg → console-icon-b.svg} +0 -0
@@ -19,10 +19,12 @@ const {
19
19
  logoLinkUrl,
20
20
  logoLinkLabel,
21
21
  title: pageTitle,
22
+ description,
23
+ openGraphImage,
22
24
  } = Astro.props;
23
25
  ---
24
26
 
25
- <BaseLayout title={pageTitle} gtmID={gtmID}>
27
+ <BaseLayout title={pageTitle} {gtmID} {description} {openGraphImage}>
26
28
  <div class="app">
27
29
  <!-- Desktop Navigation -->
28
30
  <div class="layout-container">
@@ -48,7 +50,12 @@ const {
48
50
 
49
51
  <!-- Mobile Navigation -->
50
52
  <nav aria-label="Mobile navigation">
51
- <MobileTopNav client:load {profileMenuData} />
53
+ <MobileTopNav
54
+ client:load
55
+ {profileMenuData}
56
+ {logoLinkUrl}
57
+ {logoLinkLabel}
58
+ />
52
59
  <MobileSideMenu client:load {logoLinkUrl} {logoLinkLabel}>
53
60
  <slot name="sub-nav" />
54
61
  </MobileSideMenu>
@@ -102,10 +109,6 @@ const {
102
109
  const mobileRect = mobileContent.getBoundingClientRect();
103
110
  const scrollTop =
104
111
  mobileContent.scrollTop + rect.top - mobileRect.top;
105
- console.log(
106
- '[GlobalAppLayout] Immediate mobile scroll to:',
107
- scrollTop
108
- );
109
112
  mobileContent.scrollTo({ top: scrollTop, behavior: 'auto' });
110
113
 
111
114
  setTimeout(() => {
@@ -138,11 +141,6 @@ const {
138
141
  if (mainContent) {
139
142
  const desktopAnchor = mainContent.querySelector(`[id="${anchor}"]`);
140
143
  if (desktopAnchor) {
141
- console.log(
142
- '[GlobalAppLayout] Immediate desktop scroll for:',
143
- anchor
144
- );
145
-
146
144
  try {
147
145
  // Add temporary scroll margin to account for header
148
146
  const originalScrollMargin =
@@ -200,27 +198,16 @@ const {
200
198
  // Check navigation flag first, before any components mount
201
199
  const isMainNavNavigation =
202
200
  sessionStorage.getItem('navigatingToMainNav') === 'true';
203
- console.log(
204
- '[GlobalAppLayout] DOMContentLoaded - navigation flag:',
205
- isMainNavNavigation
206
- );
207
201
 
208
202
  if (isMainNavNavigation) {
209
203
  // Clear the flag immediately
210
204
  sessionStorage.removeItem('navigatingToMainNav');
211
- console.log(
212
- '[GlobalAppLayout] Cleared navigation flag for main nav navigation'
213
- );
214
205
  // Don't clear header state here - let navigation components handle it
215
206
  }
216
207
 
217
208
  // Handle URL hash scrolling (fallback for cases where immediate scroll didn't work)
218
209
  if (window.location.hash) {
219
210
  const anchor = window.location.hash.substring(1);
220
- console.log(
221
- '[GlobalAppLayout] DOMContentLoaded fallback hash scroll for:',
222
- anchor
223
- );
224
211
 
225
212
  // Only proceed if we haven't already scrolled
226
213
  if (sessionStorage.getItem('globalLayoutScrolling') !== 'true') {
@@ -241,10 +228,6 @@ const {
241
228
  const mobileRect = mobileContent.getBoundingClientRect();
242
229
  const scrollTop =
243
230
  mobileContent.scrollTop + rect.top - mobileRect.top;
244
- console.log(
245
- '[GlobalAppLayout] Fallback mobile scroll to:',
246
- scrollTop
247
- );
248
231
  mobileContent.scrollTo({ top: scrollTop, behavior: 'auto' });
249
232
 
250
233
  setTimeout(() => {
@@ -285,11 +268,6 @@ const {
285
268
  );
286
269
  if (desktopAnchor) {
287
270
  setTimeout(() => {
288
- console.log(
289
- '[GlobalAppLayout] Fallback desktop scroll for:',
290
- anchor
291
- );
292
-
293
271
  // Try scrollIntoView first with a temporary offset
294
272
  try {
295
273
  // Add temporary scroll margin to account for header
@@ -303,43 +281,18 @@ const {
303
281
  inline: 'nearest',
304
282
  });
305
283
 
306
- console.log(
307
- '[GlobalAppLayout] Used fallback scrollIntoView for desktop'
308
- );
309
-
310
284
  // Restore original scroll margin after a delay
311
285
  setTimeout(() => {
312
286
  desktopAnchor.style.scrollMarginTop =
313
287
  originalScrollMargin;
314
288
  }, 1000);
315
289
  } catch (e) {
316
- console.log(
317
- '[GlobalAppLayout] Fallback scrollIntoView failed, using manual calculation:',
318
- e
319
- );
320
-
321
290
  // Fallback to manual calculation
322
291
  const headerHeight = 56;
323
292
  const rect = desktopAnchor.getBoundingClientRect();
324
293
  const scrollTop = window.scrollY + rect.top - headerHeight;
325
- console.log(
326
- '[GlobalAppLayout] Fallback desktop scroll calculation:',
327
- {
328
- anchor,
329
- rectTop: rect.top,
330
- windowScrollY: window.scrollY,
331
- headerHeight,
332
- scrollTop,
333
- elementText: desktopAnchor.textContent?.trim(),
334
- }
335
- );
336
-
337
294
  // Ensure scrollTop is not negative
338
295
  const finalScrollTop = Math.max(0, scrollTop);
339
- console.log(
340
- '[GlobalAppLayout] Fallback final scroll position:',
341
- finalScrollTop
342
- );
343
296
 
344
297
  window.scrollTo({ top: finalScrollTop, behavior: 'auto' });
345
298
  }
@@ -372,25 +325,14 @@ const {
372
325
  }, 100);
373
326
  }, 100);
374
327
  } else {
375
- console.log(
376
- '[GlobalAppLayout] Fallback desktop anchor not found in main-content container:',
377
- anchor
378
- );
379
328
  // Log all available anchors for debugging
380
329
  const allAnchors = mainContent.querySelectorAll('[id]');
381
- console.log(
382
- '[GlobalAppLayout] Available anchors in main-content:',
383
- Array.from(allAnchors).map(el => el.id)
384
- );
385
330
  // Clear the flag if anchor not found
386
331
  if (typeof window !== 'undefined') {
387
332
  sessionStorage.removeItem('globalLayoutScrolling');
388
333
  }
389
334
  }
390
335
  } else {
391
- console.log(
392
- '[GlobalAppLayout] Fallback desktop main-content container not found'
393
- );
394
336
  // Clear the flag if container not found
395
337
  if (typeof window !== 'undefined') {
396
338
  sessionStorage.removeItem('globalLayoutScrolling');
@@ -418,29 +360,10 @@ const {
418
360
  const wasMobile = lastWidth <= 640;
419
361
  const isMobile = currentWidth <= 640;
420
362
 
421
- console.log('[GlobalAppLayout] Resize detected:', {
422
- lastWidth,
423
- currentWidth,
424
- wasMobile,
425
- isMobile,
426
- changed: wasMobile !== isMobile,
427
- });
428
-
429
363
  if (wasMobile !== isMobile) {
430
- console.log(
431
- '[GlobalAppLayout] Layout changed from',
432
- wasMobile ? 'mobile' : 'desktop',
433
- 'to',
434
- isMobile ? 'mobile' : 'desktop'
435
- );
436
-
437
364
  // Handle anchor scrolling for layout changes
438
365
  if (window.location.hash) {
439
366
  const anchor = window.location.hash.substring(1);
440
- console.log(
441
- '[GlobalAppLayout] Layout change with URL hash:',
442
- anchor
443
- );
444
367
 
445
368
  // Wait for navigation state to update, then scroll
446
369
  setTimeout(() => {
@@ -458,10 +381,6 @@ const {
458
381
  const mobileRect = mobileContent.getBoundingClientRect();
459
382
  const scrollTop =
460
383
  mobileContent.scrollTop + rect.top - mobileRect.top;
461
- console.log(
462
- '[GlobalAppLayout] Scrolling mobile to anchor:',
463
- scrollTop
464
- );
465
384
  mobileContent.scrollTo({
466
385
  top: scrollTop,
467
386
  behavior: 'auto',
@@ -499,15 +418,6 @@ const {
499
418
  `[id="${anchor}"]`
500
419
  );
501
420
  if (desktopAnchor) {
502
- console.log(
503
- '[GlobalAppLayout] Desktop anchor found for layout change:',
504
- {
505
- anchor,
506
- elementText: desktopAnchor.textContent?.trim(),
507
- elementId: desktopAnchor.id,
508
- }
509
- );
510
-
511
421
  // Try scrollIntoView first with a temporary offset
512
422
  try {
513
423
  // Add temporary scroll margin to account for header
@@ -521,44 +431,20 @@ const {
521
431
  inline: 'nearest',
522
432
  });
523
433
 
524
- console.log(
525
- '[GlobalAppLayout] Used scrollIntoView for desktop layout change with scroll margin'
526
- );
527
-
528
434
  // Restore original scroll margin after a delay
529
435
  setTimeout(() => {
530
436
  desktopAnchor.style.scrollMarginTop =
531
437
  originalScrollMargin;
532
438
  }, 1000);
533
439
  } catch (e) {
534
- console.log(
535
- '[GlobalAppLayout] scrollIntoView failed for layout change, using manual calculation:',
536
- e
537
- );
538
-
539
440
  // Fallback to manual calculation
540
441
  const headerHeight = 56;
541
442
  const rect = desktopAnchor.getBoundingClientRect();
542
443
  const scrollTop =
543
444
  window.scrollY + rect.top - headerHeight;
544
- console.log(
545
- '[GlobalAppLayout] Desktop scroll calculation for layout change:',
546
- {
547
- anchor,
548
- rectTop: rect.top,
549
- windowScrollY: window.scrollY,
550
- headerHeight,
551
- scrollTop,
552
- elementText: desktopAnchor.textContent?.trim(),
553
- }
554
- );
555
445
 
556
446
  // Ensure scrollTop is not negative
557
447
  const finalScrollTop = Math.max(0, scrollTop);
558
- console.log(
559
- '[GlobalAppLayout] Final scroll position for layout change:',
560
- finalScrollTop
561
- );
562
448
 
563
449
  window.scrollTo({
564
450
  top: finalScrollTop,
@@ -601,11 +487,6 @@ const {
601
487
  detail: { isMobile },
602
488
  })
603
489
  );
604
- console.log(
605
- '[GlobalAppLayout] Dispatched layoutTransition event for',
606
- isMobile ? 'mobile' : 'desktop',
607
- 'layout'
608
- );
609
490
  }
610
491
 
611
492
  lastWidth = currentWidth;
@@ -14,7 +14,12 @@ body {
14
14
  }
15
15
 
16
16
  *:focus {
17
- outline-color: var(--ai-color-blue-600) !important;
17
+ outline: var(--ai-size-2) solid var(--ai-color-blue-600);
18
+ outline-offset: var(--ai-size-4);
19
+ }
20
+
21
+ *:focus:not(:focus-visible) {
22
+ outline: none;
18
23
  }
19
24
 
20
25
  a:focus {
@@ -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 {
@@ -1,9 +1,32 @@
1
+ import { getUrlFromBase } from '@gsa-tts/graymatter-ui/helpers/url.js';
2
+
1
3
  function warnIfMissing(name: string, value: string | undefined) {
2
4
  if (!value) {
3
5
  console.warn(`[getAppUrls] Environment variable for ${name} is missing!`);
4
6
  }
5
7
  }
6
8
 
9
+ function isAbsoluteUrl(url: string): boolean {
10
+ try {
11
+ new URL(url);
12
+ return true;
13
+ } catch {
14
+ return false;
15
+ }
16
+ }
17
+
18
+ function processUrl(url: string | undefined, fallback: string): string {
19
+ if (!url) {
20
+ return fallback;
21
+ }
22
+
23
+ if (isAbsoluteUrl(url)) {
24
+ return url;
25
+ }
26
+
27
+ return getUrlFromBase(url);
28
+ }
29
+
7
30
  export function getAppUrls(envArg?: Record<string, string | undefined>) {
8
31
  const env = envArg || import.meta.env;
9
32
  const fallback = '#';
@@ -18,9 +41,9 @@ export function getAppUrls(envArg?: Record<string, string | undefined>) {
18
41
  warnIfMissing('api', apiUrl);
19
42
 
20
43
  return {
21
- chat: chatUrl || fallback,
22
- console: consoleUrl || fallback,
23
- api: apiUrl || '/api',
24
- discover: discoverUrl || '/discover',
44
+ chat: processUrl(chatUrl, fallback),
45
+ console: processUrl(consoleUrl, fallback),
46
+ api: processUrl(apiUrl, getUrlFromBase('/api/documentation')),
47
+ discover: processUrl(discoverUrl, '#'),
25
48
  };
26
49
  }