@gsa-tts/graymatter-ui 0.2.8 → 0.3.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 (37) hide show
  1. package/README.md +81 -0
  2. package/assets/images/favicon-dark.ico +0 -0
  3. package/assets/images/favicon-dark.svg +7 -0
  4. package/assets/images/favicon-light.svg +7 -0
  5. package/assets/images/favicon.ico +0 -0
  6. package/assets/images/favicon.svg +5 -6
  7. package/dist/graymatter-ui.js +910 -898
  8. package/dist/graymatter-ui.umd.cjs +36 -32
  9. package/package.json +4 -4
  10. package/src/components/Button.svelte +27 -31
  11. package/src/components/Button.webcomponent.svelte +13 -11
  12. package/src/components/DesktopHeader.svelte +70 -53
  13. package/src/components/DesktopHeader.webcomponent.svelte +13 -9
  14. package/src/components/DesktopSideNav.svelte +200 -158
  15. package/src/components/DesktopSideNav.webcomponent.svelte +7 -5
  16. package/src/components/Head.astro +24 -2
  17. package/src/components/Logo.svelte +48 -41
  18. package/src/components/Logo.webcomponent.svelte +16 -16
  19. package/src/components/MobileBottomNav.svelte +102 -69
  20. package/src/components/MobileBottomNav.webcomponent.svelte +13 -4
  21. package/src/components/MobileSideMenu.svelte +70 -42
  22. package/src/components/MobileSideMenu.webcomponent.svelte +6 -4
  23. package/src/components/MobileTopNav.svelte +24 -19
  24. package/src/components/MobileTopNav.webcomponent.svelte +6 -6
  25. package/src/components/NavigationInitializer.svelte +10 -2
  26. package/src/components/ProfileMenu.svelte +116 -27
  27. package/src/components/UsaSkipNav.svelte +23 -0
  28. package/src/components/icons/ApiIcon.svelte +182 -33
  29. package/src/components/icons/ChatIcon.svelte +10 -10
  30. package/src/components/icons/CloseIcon.svelte +10 -10
  31. package/src/components/icons/ConsoleIcon.svelte +68 -13
  32. package/src/components/icons/DiscoverIcon.svelte +14 -14
  33. package/src/components/icons/HelpIcon.svelte +2 -1
  34. package/src/components/icons/MenuIcon.svelte +47 -7
  35. package/src/components/index.ts +1 -1
  36. package/src/layouts/BaseLayout.astro +1 -1
  37. package/src/components/UsaSkipNav.astro +0 -5
@@ -33,7 +33,7 @@
33
33
  apiUrl,
34
34
  chatUrl,
35
35
  consoleUrl,
36
- discoverUrl
36
+ discoverUrl,
37
37
  } = $props();
38
38
 
39
39
  let hydrated = false;
@@ -54,22 +54,31 @@
54
54
  function isNavSelected(key: NavigationItem) {
55
55
  return ssrOrHydrated($selectedItem === key, ssrSelectedItem === key);
56
56
  }
57
-
57
+
58
58
  function isNavHovered(key: string) {
59
59
  return hoveredItem === key;
60
60
  }
61
61
 
62
62
  const sideNavExpanded = $derived(() =>
63
- ssrOrHydrated($isExpanded, ssrSelectedItem ? ssrSelectedItem !== 'discover' : true)
63
+ ssrOrHydrated(
64
+ $isExpanded,
65
+ ssrSelectedItem ? ssrSelectedItem !== 'discover' : true
66
+ )
64
67
  );
65
68
  const menuBtnDisabled = $derived(() =>
66
- ssrOrHydrated($isMenuButtonDisabled, ssrSelectedItem ? ssrSelectedItem === 'discover' : false)
69
+ ssrOrHydrated(
70
+ $isMenuButtonDisabled,
71
+ ssrSelectedItem ? ssrSelectedItem === 'discover' : false
72
+ )
67
73
  );
68
74
  const menuBtnOpen = $derived(() =>
69
- ssrOrHydrated($isExpanded, ssrSelectedItem ? ssrSelectedItem !== 'discover' : true)
75
+ ssrOrHydrated(
76
+ $isExpanded,
77
+ ssrSelectedItem ? ssrSelectedItem !== 'discover' : true
78
+ )
70
79
  );
71
- const menuBtnHovered = $derived(() =>
72
- canHover && menuButtonHovered && !menuBtnDisabled()
80
+ const menuBtnHovered = $derived(
81
+ () => canHover && menuButtonHovered && !menuBtnDisabled()
73
82
  );
74
83
 
75
84
  onMount(() => {
@@ -89,19 +98,19 @@
89
98
  mq.addEventListener('change', e => {
90
99
  canHover = e.matches;
91
100
  });
92
-
101
+
93
102
  // Listen for layout transitions
94
103
  const handleLayoutTransition = (event: Event) => {
95
104
  const customEvent = event as CustomEvent;
96
105
  const { isMobile } = customEvent.detail;
97
-
106
+
98
107
  if (isMobile) {
99
108
  // Switching to mobile: close navigation
100
109
  navigationStore.setExpanded(false);
101
110
  } else {
102
111
  // Switching to desktop: open navigation if on non-discover page
103
112
  const currentItem = $selectedItem;
104
-
113
+
105
114
  if (currentItem && currentItem !== 'discover') {
106
115
  navigationStore.setExpanded(true);
107
116
  } else {
@@ -109,9 +118,9 @@
109
118
  }
110
119
  }
111
120
  };
112
-
121
+
113
122
  window.addEventListener('layoutTransition', handleLayoutTransition);
114
-
123
+
115
124
  // Add Escape key handler for nav collapse, but ignore if focus is in profile context menu
116
125
  const handleEscape = (e: KeyboardEvent) => {
117
126
  const active = document.activeElement;
@@ -124,7 +133,7 @@
124
133
  }
125
134
  };
126
135
  window.addEventListener('keydown', handleEscape);
127
-
136
+
128
137
  return () => {
129
138
  window.removeEventListener('layoutTransition', handleLayoutTransition);
130
139
  window.removeEventListener('keydown', handleEscape);
@@ -138,62 +147,77 @@
138
147
  onNavToggle?.({ expanded: $isExpanded });
139
148
  }
140
149
 
141
- function handleNavItemClick(item: NavigationItem) {
150
+ function handleNavItemClick(item: NavigationItem) {
142
151
  // Set navigation flag immediately to prevent header restoration
143
152
  if (item !== 'discover' && typeof window !== 'undefined') {
144
153
  sessionStorage.setItem('navigatingToMainNav', 'true');
145
154
  }
146
-
155
+
147
156
  navigationStore.setSelectedItem(item);
148
-
157
+
149
158
  // Clear header state for main navigation items (including discover)
150
159
  if (item !== 'discover') {
151
160
  try {
152
- import('@gsa-tts/graymatter-ui/stores/navigationStore').then(({ selectedSubNavItemTitle }) => {
153
- // Clear the store value immediately
154
- selectedSubNavItemTitle.set('');
155
- if (typeof window !== 'undefined') {
156
- sessionStorage.removeItem('subNav-selectedTitle');
157
- sessionStorage.removeItem('subNav-selectedId');
158
- }
159
-
160
- // Set default header from first submenu item after a short delay
161
- setTimeout(() => {
162
- const mainContent = document.getElementById('main-content');
163
- if (mainContent) {
164
- const firstSection = mainContent.querySelector('h2[id], h3[id], h4[id], h5[id], h6[id]');
165
- if (firstSection && firstSection.textContent) {
166
- const firstSectionTitle = firstSection.textContent.trim();
167
- selectedSubNavItemTitle.set(firstSectionTitle);
168
- if (typeof window !== 'undefined') {
169
- sessionStorage.setItem('subNav-selectedTitle', JSON.stringify(firstSectionTitle));
161
+ import('@gsa-tts/graymatter-ui/stores/navigationStore')
162
+ .then(({ selectedSubNavItemTitle }) => {
163
+ // Clear the store value immediately
164
+ selectedSubNavItemTitle.set('');
165
+ if (typeof window !== 'undefined') {
166
+ sessionStorage.removeItem('subNav-selectedTitle');
167
+ sessionStorage.removeItem('subNav-selectedId');
168
+ }
169
+
170
+ // Set default header from first submenu item after a short delay
171
+ setTimeout(() => {
172
+ const mainContent = document.getElementById('main-content');
173
+ if (mainContent) {
174
+ const firstSection = mainContent.querySelector(
175
+ 'h2[id], h3[id], h4[id], h5[id], h6[id]'
176
+ );
177
+ if (firstSection && firstSection.textContent) {
178
+ const firstSectionTitle = firstSection.textContent.trim();
179
+ selectedSubNavItemTitle.set(firstSectionTitle);
180
+ if (typeof window !== 'undefined') {
181
+ sessionStorage.setItem(
182
+ 'subNav-selectedTitle',
183
+ JSON.stringify(firstSectionTitle)
184
+ );
185
+ }
170
186
  }
171
187
  }
172
- }
173
- }, 200); // Delay to ensure page content is loaded
174
- }).catch((err) => {
175
- console.log('[DesktopSideNav] Error clearing header state:', err);
176
- });
188
+ }, 200); // Delay to ensure page content is loaded
189
+ })
190
+ .catch(err => {
191
+ console.log('[DesktopSideNav] Error clearing header state:', err);
192
+ });
177
193
  } catch (err) {
178
194
  console.log('[DesktopSideNav] Import failed for clearing state:', err);
179
195
  }
180
196
  } else {
181
197
  // Clear header state for Discover page
182
198
  try {
183
- import('@gsa-tts/graymatter-ui/stores/navigationStore').then(({ selectedSubNavItemTitle }) => {
184
- selectedSubNavItemTitle.set('');
185
- if (typeof window !== 'undefined') {
186
- sessionStorage.removeItem('subNav-selectedTitle');
187
- sessionStorage.removeItem('subNav-selectedId');
188
- }
189
- }).catch((err) => {
190
- console.log('[DesktopSideNav] Error clearing header state for Discover:', err);
191
- });
199
+ import('@gsa-tts/graymatter-ui/stores/navigationStore')
200
+ .then(({ selectedSubNavItemTitle }) => {
201
+ selectedSubNavItemTitle.set('');
202
+ if (typeof window !== 'undefined') {
203
+ sessionStorage.removeItem('subNav-selectedTitle');
204
+ sessionStorage.removeItem('subNav-selectedId');
205
+ }
206
+ })
207
+ .catch(err => {
208
+ console.log(
209
+ '[DesktopSideNav] Error clearing header state for Discover:',
210
+ err
211
+ );
212
+ });
192
213
  } catch (err) {
193
- console.log('[DesktopSideNav] Import failed for clearing Discover state:', err);
214
+ console.log(
215
+ '[DesktopSideNav] Import failed for clearing Discover state:',
216
+ err
217
+ );
194
218
  }
195
219
  }
196
-
220
+
197
221
  onNavItemClick?.({ item, expanded: $isExpanded });
198
222
  }
199
223
 
@@ -244,7 +268,9 @@
244
268
  onmouseleave={() => (menuButtonHovered = false)}
245
269
  onfocus={() => (menuButtonHovered = true)}
246
270
  onblur={() => (menuButtonHovered = false)}
247
- aria-label={sideNavExpanded() ? 'Close navigation menu' : 'Open navigation menu'}
271
+ aria-label={sideNavExpanded()
272
+ ? 'Close navigation menu'
273
+ : 'Open navigation menu'}
248
274
  aria-expanded={sideNavExpanded() ? 'true' : 'false'}
249
275
  >
250
276
  <div class="icon-container" part="icon-container">
@@ -260,97 +286,109 @@
260
286
  </div>
261
287
 
262
288
  {#if showAppIcons}
263
- <div class="nav-items" part="nav-items">
264
- <a
265
- href={discoverUrl || urls.discover}
266
- class="nav-item discover-item"
267
- class:selected={isNavSelected('discover')}
268
- class:hovered={isNavHovered('discover')}
269
- onclick={() => handleNavItemClick('discover')}
270
- onkeydown={e => { handleKeyDown(e, 'discover'); handleNavKeyDown(e, 0); }}
271
- onmouseenter={() => (hoveredItem = 'discover')}
272
- onmouseleave={() => (hoveredItem = null)}
273
- aria-current={isNavSelected('discover') ? 'page' : undefined}
274
- part="discover-item"
275
- bind:this={discoverNavRef}
276
- >
277
- <div class="icon-container" part="discover-icon-container">
278
- <div class="icon-wrapper">
279
- <DiscoverIcon isSelected={isNavSelected('discover')} />
289
+ <div class="nav-items" part="nav-items">
290
+ <a
291
+ href={discoverUrl || urls.discover}
292
+ class="nav-item discover-item"
293
+ class:selected={isNavSelected('discover')}
294
+ class:hovered={isNavHovered('discover')}
295
+ onclick={() => handleNavItemClick('discover')}
296
+ onkeydown={e => {
297
+ handleKeyDown(e, 'discover');
298
+ handleNavKeyDown(e, 0);
299
+ }}
300
+ onmouseenter={() => (hoveredItem = 'discover')}
301
+ onmouseleave={() => (hoveredItem = null)}
302
+ aria-current={isNavSelected('discover') ? 'page' : undefined}
303
+ part="discover-item"
304
+ bind:this={discoverNavRef}
305
+ >
306
+ <div class="icon-container" part="discover-icon-container">
307
+ <div class="icon-wrapper">
308
+ <DiscoverIcon isSelected={isNavSelected('discover')} />
309
+ </div>
280
310
  </div>
281
- </div>
282
- <span class="nav-text">Discover</span>
283
- </a>
284
- <a
285
- href={chatUrl || urls.chat}
286
- class="nav-item chat-item"
287
- class:selected={isNavSelected('chat')}
288
- class:hovered={isNavHovered('chat')}
289
- onclick={() => handleNavItemClick('chat')}
290
- onkeydown={e => { handleKeyDown(e, 'chat'); handleNavKeyDown(e, 1); }}
291
- onmouseenter={() => (hoveredItem = 'chat')}
292
- onmouseleave={() => (hoveredItem = null)}
293
- aria-current={isNavSelected('chat') ? 'page' : undefined}
294
- part="chat-item"
295
- bind:this={chatNavRef}
296
- >
297
- <div class="icon-container" part="chat-icon-container">
298
- <div class="icon-wrapper">
299
- <ChatIcon isSelected={isNavSelected('chat') as boolean} />
311
+ <span class="nav-text">Discover</span>
312
+ </a>
313
+ <a
314
+ href={chatUrl || urls.chat}
315
+ class="nav-item chat-item"
316
+ class:selected={isNavSelected('chat')}
317
+ class:hovered={isNavHovered('chat')}
318
+ onclick={() => handleNavItemClick('chat')}
319
+ onkeydown={e => {
320
+ handleKeyDown(e, 'chat');
321
+ handleNavKeyDown(e, 1);
322
+ }}
323
+ onmouseenter={() => (hoveredItem = 'chat')}
324
+ onmouseleave={() => (hoveredItem = null)}
325
+ aria-current={isNavSelected('chat') ? 'page' : undefined}
326
+ part="chat-item"
327
+ bind:this={chatNavRef}
328
+ >
329
+ <div class="icon-container" part="chat-icon-container">
330
+ <div class="icon-wrapper">
331
+ <ChatIcon isSelected={isNavSelected('chat') as boolean} />
332
+ </div>
300
333
  </div>
301
- </div>
302
- <span class="nav-text">Chat</span>
303
- </a>
304
-
305
- <a
306
- href={consoleUrl || urls.console}
307
- class="nav-item console-item"
308
- class:selected={isNavSelected('console')}
309
- class:hovered={isNavHovered('console')}
310
- onclick={() => handleNavItemClick('console')}
311
- onkeydown={e => { handleKeyDown(e, 'console'); handleNavKeyDown(e, 2); }}
312
- onmouseenter={() => (hoveredItem = 'console')}
313
- onmouseleave={() => (hoveredItem = null)}
314
- aria-current={isNavSelected('console') ? 'page' : undefined}
315
- part="console-item"
316
- bind:this={consoleNavRef}
317
- >
318
- <div class="icon-container" part="console-icon-container">
319
- <div class="icon-wrapper">
320
- <ConsoleIcon isSelected={isNavSelected('console') as boolean} />
334
+ <span class="nav-text">Chat</span>
335
+ </a>
336
+
337
+ <a
338
+ href={consoleUrl || urls.console}
339
+ class="nav-item console-item"
340
+ class:selected={isNavSelected('console')}
341
+ class:hovered={isNavHovered('console')}
342
+ onclick={() => handleNavItemClick('console')}
343
+ onkeydown={e => {
344
+ handleKeyDown(e, 'console');
345
+ handleNavKeyDown(e, 2);
346
+ }}
347
+ onmouseenter={() => (hoveredItem = 'console')}
348
+ onmouseleave={() => (hoveredItem = null)}
349
+ aria-current={isNavSelected('console') ? 'page' : undefined}
350
+ part="console-item"
351
+ bind:this={consoleNavRef}
352
+ >
353
+ <div class="icon-container" part="console-icon-container">
354
+ <div class="icon-wrapper">
355
+ <ConsoleIcon isSelected={isNavSelected('console') as boolean} />
356
+ </div>
321
357
  </div>
322
- </div>
323
- <span class="nav-text">Console</span>
324
- </a>
325
-
326
- <a
327
- href={apiUrl || urls.api}
328
- class="nav-item api-item"
329
- class:selected={isNavSelected('api')}
330
- class:hovered={isNavHovered('api')}
331
- onclick={() => handleNavItemClick('api')}
332
- onkeydown={e => { handleKeyDown(e, 'api'); handleNavKeyDown(e, 3); }}
333
- onmouseenter={() => (hoveredItem = 'api')}
334
- onmouseleave={() => (hoveredItem = null)}
335
- aria-current={isNavSelected('api') ? 'page' : undefined}
336
- part="api-item"
337
- bind:this={apiNavRef}
338
- >
339
- <div class="icon-container" part="api-icon-container">
340
- <div class="icon-wrapper">
341
- <ApiIcon isSelected={isNavSelected('api')} />
358
+ <span class="nav-text">Console</span>
359
+ </a>
360
+
361
+ <a
362
+ href={apiUrl || urls.api}
363
+ class="nav-item api-item"
364
+ class:selected={isNavSelected('api')}
365
+ class:hovered={isNavHovered('api')}
366
+ onclick={() => handleNavItemClick('api')}
367
+ onkeydown={e => {
368
+ handleKeyDown(e, 'api');
369
+ handleNavKeyDown(e, 3);
370
+ }}
371
+ onmouseenter={() => (hoveredItem = 'api')}
372
+ onmouseleave={() => (hoveredItem = null)}
373
+ aria-current={isNavSelected('api') ? 'page' : undefined}
374
+ part="api-item"
375
+ bind:this={apiNavRef}
376
+ >
377
+ <div class="icon-container" part="api-icon-container">
378
+ <div class="icon-wrapper">
379
+ <ApiIcon isSelected={isNavSelected('api')} />
380
+ </div>
342
381
  </div>
343
- </div>
344
- <span class="nav-text">API</span>
345
- </a>
346
- </div>
382
+ <span class="nav-text">API</span>
383
+ </a>
384
+ </div>
347
385
  {/if}
348
386
  </div>
349
387
 
350
388
  {#if profileMenuData}
351
- <div class="nav-footer" part="nav-footer">
352
- <!-- TODO: Add help icon back in when we have decided on full functionality-->
353
- <!-- <div class="nav-footer-icon-container">
389
+ <div class="nav-footer" part="nav-footer">
390
+ <!-- TODO: Add help icon back in when we have decided on full functionality-->
391
+ <!-- <div class="nav-footer-icon-container">
354
392
  <button
355
393
  type="button"
356
394
  class="nav-footer-icon-inner"
@@ -366,19 +404,23 @@
366
404
  </div>
367
405
  </button>
368
406
  </div> -->
369
- <div class="nav-footer-profile-container">
370
- <ProfileMenu
371
- userMeta={profileMenuData?.userMeta}
372
- menuItems={profileMenuData?.menuItems}
373
- ariaLabel="Open profile menu"
374
- menuAlign="desktop"
375
- />
407
+ <div class="nav-footer-profile-container">
408
+ <ProfileMenu
409
+ userMeta={profileMenuData?.userMeta}
410
+ menuItems={profileMenuData?.menuItems}
411
+ ariaLabel="Open profile menu"
412
+ menuAlign="desktop"
413
+ />
414
+ </div>
376
415
  </div>
377
- </div>
378
416
  {/if}
379
417
  </div>
380
418
 
381
- <div class="expanded-content drawer-anim" class:open={sideNavExpanded()} part="expanded-content">
419
+ <div
420
+ class="expanded-content drawer-anim"
421
+ class:open={sideNavExpanded()}
422
+ part="expanded-content"
423
+ >
382
424
  {#if sideNavExpanded()}
383
425
  <div class="drawer-content" part="drawer-content">
384
426
  <nav aria-label="Sub navigation" part="sub-navigation">
@@ -394,8 +436,7 @@
394
436
  max-width: 0;
395
437
  overflow: hidden;
396
438
  pointer-events: none;
397
- transition:
398
- max-width 0.2s cubic-bezier(.4, 0, .2, 1);
439
+ transition: max-width var(--ai-duration-fast) cubic-bezier(0.4, 0, 0.2, 1);
399
440
  }
400
441
 
401
442
  .expanded-content.drawer-anim.open {
@@ -425,7 +466,7 @@
425
466
  background: none;
426
467
  cursor: pointer;
427
468
  border-radius: var(--ai-size-8);
428
- transition: background-color 0.2s ease;
469
+ transition: background-color var(--ai-transition-ease-fast);
429
470
  }
430
471
 
431
472
  .menu-button:disabled,
@@ -434,7 +475,7 @@
434
475
  opacity: 0.5;
435
476
  background-color: transparent;
436
477
  }
437
-
478
+
438
479
  .side-nav-container {
439
480
  display: flex;
440
481
  flex-shrink: 0;
@@ -506,7 +547,6 @@
506
547
  margin-top: auto;
507
548
  }
508
549
 
509
-
510
550
  .menu-section {
511
551
  display: flex;
512
552
  padding: var(--ai-size-4);
@@ -524,7 +564,7 @@
524
564
  border: none;
525
565
  cursor: pointer;
526
566
  opacity: 1;
527
- transition: opacity 0.2s ease;
567
+ transition: opacity var(--ai-transition-ease-fast);
528
568
  will-change: opacity;
529
569
  }
530
570
 
@@ -586,8 +626,9 @@
586
626
  flex-shrink: 0;
587
627
  position: relative;
588
628
  contain: layout style;
589
- transition: background-color 0.3s ease,
590
- border-radius 0.3s ease;
629
+ transition:
630
+ background-color var(--ai-transition-ease-medium),
631
+ border-radius var(--ai-transition-ease-medium);
591
632
  }
592
633
 
593
634
  .icon-wrapper {
@@ -600,7 +641,7 @@
600
641
  aspect-ratio: 1/1;
601
642
  position: relative;
602
643
  overflow: hidden;
603
- transition: transform 0.3s ease;
644
+ transition: transform var(--ai-transition-ease-medium);
604
645
  }
605
646
 
606
647
  .icon-wrapper :global(svg) {
@@ -611,15 +652,16 @@
611
652
  top: 50%;
612
653
  left: 50%;
613
654
  transform: translate(-50%, -50%);
614
- transition: all 0.3s ease;
655
+ transition: all var(--ai-transition-ease-medium);
615
656
  }
616
657
 
617
658
  .icon-wrapper :global(svg path) {
618
659
  stroke-width: 1.5;
619
660
  vector-effect: non-scaling-stroke;
620
- transition: stroke 0.3s ease,
621
- fill 0.3s ease,
622
- stroke-width 0.3s ease;
661
+ transition:
662
+ stroke var(--ai-transition-ease-medium),
663
+ fill var(--ai-transition-ease-medium),
664
+ stroke-width var(--ai-transition-ease-medium);
623
665
  }
624
666
 
625
667
  .nav-text {
@@ -654,7 +696,7 @@
654
696
  padding: var(--ai-size-4);
655
697
  text-decoration: none;
656
698
  color: var(--ai-color-neutral-600);
657
- transition: color 0.2s ease;
699
+ transition: color var(--ai-transition-ease-fast);
658
700
  height: 100%;
659
701
  }
660
702
 
@@ -692,7 +734,7 @@
692
734
  background: none;
693
735
  border: none;
694
736
  cursor: pointer;
695
- transition: background-color 0.3s ease, border-radius 0.3s ease;
737
+ transition: background-color var(--ai-transition-ease-medium), border-radius var(--ai-transition-ease-medium);
696
738
  } */
697
739
  /* .nav-footer-icon-inner:hover,
698
740
  .nav-footer-icon-inner:focus {
@@ -1,6 +1,8 @@
1
- <svelte:options customElement={{
2
- tag: 'graymatter-desktop-side-nav'
3
- }} />
1
+ <svelte:options
2
+ customElement={{
3
+ tag: 'graymatter-desktop-side-nav',
4
+ }}
5
+ />
4
6
 
5
7
  <script lang="ts">
6
8
  import DesktopSideNav from './DesktopSideNav.svelte';
@@ -10,12 +12,12 @@
10
12
  ssrSelectedItem,
11
13
  onNavToggle,
12
14
  onNavItemClick,
13
- showAppIcons = true,
15
+ showAppIcons = true,
14
16
  profileMenuData,
15
17
  apiUrl,
16
18
  chatUrl,
17
19
  consoleUrl,
18
- discoverUrl
20
+ discoverUrl,
19
21
  } = $props();
20
22
  </script>
21
23
 
@@ -5,8 +5,30 @@ import { getUrlFromBase } from '@gsa-tts/graymatter-ui/helpers';
5
5
  ---
6
6
 
7
7
  <meta name="viewport" content="width=device-width" />
8
- <link rel="icon" sizes="any" href=`${getUrlFromBase('favicon.ico')}` />
9
- <link rel="icon" type="image/svg+xml" href=`${getUrlFromBase('favicon.svg')}` />
8
+ <link
9
+ rel="icon"
10
+ sizes="any"
11
+ href=`${getUrlFromBase('/assets/images/favicon-light.ico')}`
12
+ media="(prefers-color-scheme: light)"
13
+ />
14
+ <link
15
+ rel="icon"
16
+ type="image/svg+xml"
17
+ href=`${getUrlFromBase('/assets/images/favicon-light.svg')}`
18
+ media="(prefers-color-scheme: light)"
19
+ />
20
+ <link
21
+ rel="icon"
22
+ sizes="any"
23
+ href=`${getUrlFromBase('/assets/images/favicon-dark.ico')}`
24
+ media="(prefers-color-scheme: dark)"
25
+ />
26
+ <link
27
+ rel="icon"
28
+ type="image/svg+xml"
29
+ href=`${getUrlFromBase('/assets/images/favicon-dark.svg')}`
30
+ media="(prefers-color-scheme: dark)"
31
+ />
10
32
  <meta name="generator" content={Astro.generator} />
11
33
  <title>{title}</title>
12
34
  <script is:inline>