@gsa-tts/graymatter-ui 0.2.7 → 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 (38) 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 +1663 -1628
  8. package/dist/graymatter-ui.umd.cjs +80 -33
  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 +209 -166
  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/styles/base/global.css +7 -1
  38. package/src/components/UsaSkipNav.astro +0 -5
@@ -20,7 +20,7 @@
20
20
  import MenuIcon from './icons/MenuIcon.svelte';
21
21
  import ProfileMenu from './ProfileMenu.svelte';
22
22
  import { getAppUrls } from '../utils/getAppUrls';
23
- import HelpIcon from './icons/HelpIcon.svelte';
23
+ // import HelpIcon from './icons/HelpIcon.svelte';
24
24
  const urls = getAppUrls();
25
25
 
26
26
  const {
@@ -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;
@@ -41,7 +41,7 @@
41
41
  let hoveredItem = $state<string | null>(null);
42
42
  let menuButtonHovered = $state(false);
43
43
  let canHover = $state(false);
44
- let helpIconHovered = $state(false);
44
+ // let helpIconHovered = $state(false);
45
45
  let discoverNavRef = $state<HTMLAnchorElement | null>(null);
46
46
  let chatNavRef = $state<HTMLAnchorElement | null>(null);
47
47
  let consoleNavRef = $state<HTMLAnchorElement | null>(null);
@@ -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,96 +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
- <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">
353
392
  <button
354
393
  type="button"
355
394
  class="nav-footer-icon-inner"
@@ -364,20 +403,24 @@
364
403
  <HelpIcon isHovered={helpIconHovered} />
365
404
  </div>
366
405
  </button>
406
+ </div> -->
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>
367
415
  </div>
368
- <div class="nav-footer-profile-container">
369
-
370
- <ProfileMenu
371
- userMeta={profileMenuData?.userMeta}
372
- menuItems={profileMenuData?.menuItems}
373
- ariaLabel="Open profile menu"
374
- />
375
- </div>
376
- </div>
377
416
  {/if}
378
417
  </div>
379
418
 
380
- <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
+ >
381
424
  {#if sideNavExpanded()}
382
425
  <div class="drawer-content" part="drawer-content">
383
426
  <nav aria-label="Sub navigation" part="sub-navigation">
@@ -393,8 +436,7 @@
393
436
  max-width: 0;
394
437
  overflow: hidden;
395
438
  pointer-events: none;
396
- transition:
397
- 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);
398
440
  }
399
441
 
400
442
  .expanded-content.drawer-anim.open {
@@ -424,7 +466,7 @@
424
466
  background: none;
425
467
  cursor: pointer;
426
468
  border-radius: var(--ai-size-8);
427
- transition: background-color 0.2s ease;
469
+ transition: background-color var(--ai-transition-ease-fast);
428
470
  }
429
471
 
430
472
  .menu-button:disabled,
@@ -433,7 +475,7 @@
433
475
  opacity: 0.5;
434
476
  background-color: transparent;
435
477
  }
436
-
478
+
437
479
  .side-nav-container {
438
480
  display: flex;
439
481
  flex-shrink: 0;
@@ -505,7 +547,6 @@
505
547
  margin-top: auto;
506
548
  }
507
549
 
508
-
509
550
  .menu-section {
510
551
  display: flex;
511
552
  padding: var(--ai-size-4);
@@ -523,7 +564,7 @@
523
564
  border: none;
524
565
  cursor: pointer;
525
566
  opacity: 1;
526
- transition: opacity 0.2s ease;
567
+ transition: opacity var(--ai-transition-ease-fast);
527
568
  will-change: opacity;
528
569
  }
529
570
 
@@ -585,8 +626,9 @@
585
626
  flex-shrink: 0;
586
627
  position: relative;
587
628
  contain: layout style;
588
- transition: background-color 0.3s ease,
589
- border-radius 0.3s ease;
629
+ transition:
630
+ background-color var(--ai-transition-ease-medium),
631
+ border-radius var(--ai-transition-ease-medium);
590
632
  }
591
633
 
592
634
  .icon-wrapper {
@@ -599,7 +641,7 @@
599
641
  aspect-ratio: 1/1;
600
642
  position: relative;
601
643
  overflow: hidden;
602
- transition: transform 0.3s ease;
644
+ transition: transform var(--ai-transition-ease-medium);
603
645
  }
604
646
 
605
647
  .icon-wrapper :global(svg) {
@@ -610,15 +652,16 @@
610
652
  top: 50%;
611
653
  left: 50%;
612
654
  transform: translate(-50%, -50%);
613
- transition: all 0.3s ease;
655
+ transition: all var(--ai-transition-ease-medium);
614
656
  }
615
657
 
616
658
  .icon-wrapper :global(svg path) {
617
659
  stroke-width: 1.5;
618
660
  vector-effect: non-scaling-stroke;
619
- transition: stroke 0.3s ease,
620
- fill 0.3s ease,
621
- 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);
622
665
  }
623
666
 
624
667
  .nav-text {
@@ -653,7 +696,7 @@
653
696
  padding: var(--ai-size-4);
654
697
  text-decoration: none;
655
698
  color: var(--ai-color-neutral-600);
656
- transition: color 0.2s ease;
699
+ transition: color var(--ai-transition-ease-fast);
657
700
  height: 100%;
658
701
  }
659
702
 
@@ -661,7 +704,7 @@
661
704
  color: var(--ai-color-neutral-700);
662
705
  }
663
706
 
664
- .nav-footer-icon-container {
707
+ /* .nav-footer-icon-container {
665
708
  display: flex;
666
709
  padding: 0 var(--ai-size-4);
667
710
  flex-direction: column;
@@ -669,7 +712,7 @@
669
712
  align-items: center;
670
713
  gap: var(--ai-size-4);
671
714
  align-self: stretch;
672
- }
715
+ } */
673
716
 
674
717
  .nav-footer-profile-container {
675
718
  display: flex;
@@ -680,7 +723,7 @@
680
723
  gap: var(--ai-size-4);
681
724
  align-self: stretch;
682
725
  }
683
- .nav-footer-icon-inner {
726
+ /* .nav-footer-icon-inner {
684
727
  display: flex;
685
728
  width: var(--ai-size-40);
686
729
  height: var(--ai-size-40);
@@ -691,9 +734,9 @@
691
734
  background: none;
692
735
  border: none;
693
736
  cursor: pointer;
694
- transition: background-color 0.3s ease, border-radius 0.3s ease;
695
- }
696
- .nav-footer-icon-inner:hover,
737
+ transition: background-color var(--ai-transition-ease-medium), border-radius var(--ai-transition-ease-medium);
738
+ } */
739
+ /* .nav-footer-icon-inner:hover,
697
740
  .nav-footer-icon-inner:focus {
698
741
  background-color: var(--ai-color-steel-300);
699
742
  border-radius: var(--ai-size-4);
@@ -713,5 +756,5 @@
713
756
  display: flex;
714
757
  align-items: center;
715
758
  justify-content: center;
716
- }
759
+ } */
717
760
  </style>
@@ -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>