@gsa-tts/graymatter-ui 0.4.9 → 0.4.11
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/dist/graymatter-ui.js +2095 -1969
- package/dist/graymatter-ui.umd.cjs +27 -22
- package/package.json +1 -1
- package/src/components/DesktopSideNav.svelte +71 -17
- package/src/components/MobileBottomNav.svelte +1 -1
- package/src/components/MobileTopNav.svelte +100 -1
- package/src/components/MobileTopNav.webcomponent.svelte +8 -2
- package/src/components/icons/HelpIcon.svelte +2 -2
- package/src/layouts/GlobalAppLayout.astro +2 -1
package/package.json
CHANGED
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
} = $props();
|
|
39
39
|
|
|
40
40
|
const helpUrl = supplementalMenuData?.help?.url?.trim();
|
|
41
|
+
const isHelpSelected = $derived(() => get(selectedSubNavItemId) === 'help');
|
|
41
42
|
|
|
42
43
|
let hydrated = false;
|
|
43
44
|
let navContainer: HTMLDivElement;
|
|
@@ -169,9 +170,40 @@
|
|
|
169
170
|
);
|
|
170
171
|
};
|
|
171
172
|
|
|
173
|
+
// Detect help page and set selection state
|
|
174
|
+
const checkHelpPage = () => {
|
|
175
|
+
// Skip check for hash links - they stay on the same page
|
|
176
|
+
if (!helpUrl || helpUrl === '#' || helpUrl.startsWith('#')) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const location = (
|
|
181
|
+
globalThis as { location?: { pathname?: string; origin?: string } }
|
|
182
|
+
).location;
|
|
183
|
+
if (location?.origin && location?.pathname) {
|
|
184
|
+
const helpPath = getPathname(helpUrl, location.origin);
|
|
185
|
+
if (helpPath && location.pathname === helpPath) {
|
|
186
|
+
selectedSubNavItemId.set('help');
|
|
187
|
+
} else if (
|
|
188
|
+
get(selectedSubNavItemId) === 'help' &&
|
|
189
|
+
helpPath &&
|
|
190
|
+
location.pathname !== helpPath
|
|
191
|
+
) {
|
|
192
|
+
// Clear help selection if we navigated away from help page
|
|
193
|
+
selectedSubNavItemId.set(null);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
checkHelpPage();
|
|
199
|
+
|
|
200
|
+
// Also listen for popstate events (back/forward navigation)
|
|
201
|
+
window.addEventListener('popstate', checkHelpPage);
|
|
202
|
+
|
|
172
203
|
return () => {
|
|
173
204
|
window.removeEventListener('layoutTransition', handleLayoutTransition);
|
|
174
205
|
window.removeEventListener('keydown', handleEscape);
|
|
206
|
+
window.removeEventListener('popstate', checkHelpPage);
|
|
175
207
|
if (eventListenerCleanup) {
|
|
176
208
|
eventListenerCleanup();
|
|
177
209
|
}
|
|
@@ -179,6 +211,25 @@
|
|
|
179
211
|
}
|
|
180
212
|
});
|
|
181
213
|
|
|
214
|
+
function getPathname(url: string, baseOrigin: string) {
|
|
215
|
+
try {
|
|
216
|
+
return new URL(url, baseOrigin).pathname;
|
|
217
|
+
} catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function handleHelpClick(event: MouseEvent) {
|
|
223
|
+
selectedSubNavItemId.set('help');
|
|
224
|
+
|
|
225
|
+
// If it's a hash link, prevent default to maintain state on same page
|
|
226
|
+
if (helpUrl === '#' || helpUrl?.startsWith('#')) {
|
|
227
|
+
event.preventDefault();
|
|
228
|
+
// State is already set above, so it will persist
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
182
233
|
function toggleNav() {
|
|
183
234
|
if ($isMenuButtonDisabled) return;
|
|
184
235
|
navigationStore.toggleExpanded();
|
|
@@ -437,14 +488,19 @@
|
|
|
437
488
|
>
|
|
438
489
|
<a
|
|
439
490
|
class="help-link"
|
|
440
|
-
class:selected={
|
|
441
|
-
aria-current={
|
|
491
|
+
class:selected={isHelpSelected()}
|
|
492
|
+
aria-current={isHelpSelected()}
|
|
442
493
|
href={helpUrl}
|
|
443
494
|
part="help-link"
|
|
444
495
|
title="Help"
|
|
445
496
|
aria-label="Help"
|
|
497
|
+
onclick={handleHelpClick}
|
|
446
498
|
>
|
|
447
|
-
<
|
|
499
|
+
<div class="icon-container" part="help-icon-container">
|
|
500
|
+
<div class="icon-wrapper">
|
|
501
|
+
<HelpIcon isSelected={isHelpSelected()} />
|
|
502
|
+
</div>
|
|
503
|
+
</div>
|
|
448
504
|
</a>
|
|
449
505
|
</div>
|
|
450
506
|
{/if}
|
|
@@ -624,7 +680,8 @@
|
|
|
624
680
|
}
|
|
625
681
|
|
|
626
682
|
.menu-button:focus .icon-container,
|
|
627
|
-
.nav-item:focus .icon-container
|
|
683
|
+
.nav-item:focus .icon-container,
|
|
684
|
+
.help-link:focus .icon-container {
|
|
628
685
|
outline: var(--ai-size-2) solid var(--ai-color-blue-600);
|
|
629
686
|
outline-offset: var(--ai-size-2);
|
|
630
687
|
border-radius: var(--ai-size-4);
|
|
@@ -632,7 +689,8 @@
|
|
|
632
689
|
|
|
633
690
|
/* Hide focus outline on click */
|
|
634
691
|
.menu-button:focus:not(:focus-visible) .icon-container,
|
|
635
|
-
.nav-item:focus:not(:focus-visible) .icon-container
|
|
692
|
+
.nav-item:focus:not(:focus-visible) .icon-container,
|
|
693
|
+
.help-link:focus:not(:focus-visible) .icon-container {
|
|
636
694
|
outline: none;
|
|
637
695
|
}
|
|
638
696
|
|
|
@@ -726,7 +784,9 @@
|
|
|
726
784
|
.nav-item.selected .icon-container,
|
|
727
785
|
.nav-item.selected.hovered .icon-container,
|
|
728
786
|
.menu-button:hover .icon-container,
|
|
729
|
-
.menu-button:active .icon-container
|
|
787
|
+
.menu-button:active .icon-container,
|
|
788
|
+
.help-link:hover .icon-container,
|
|
789
|
+
.help-link.selected .icon-container {
|
|
730
790
|
background-color: var(--ai-color-steel-300);
|
|
731
791
|
border-radius: var(--ai-size-4);
|
|
732
792
|
}
|
|
@@ -767,20 +827,14 @@
|
|
|
767
827
|
}
|
|
768
828
|
|
|
769
829
|
.help-link {
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
830
|
+
display: flex;
|
|
831
|
+
align-items: center;
|
|
832
|
+
justify-content: center;
|
|
833
|
+
text-decoration: none;
|
|
834
|
+
color: inherit;
|
|
773
835
|
}
|
|
774
836
|
|
|
775
837
|
.help-link :global(svg) {
|
|
776
838
|
display: block;
|
|
777
839
|
}
|
|
778
|
-
|
|
779
|
-
.help-link:hover {
|
|
780
|
-
background: var(--ai-color-steel-300);
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
.help-link:is(.selected) {
|
|
784
|
-
background-color: var(--ai-color-steel-300);
|
|
785
|
-
}
|
|
786
840
|
</style>
|
|
@@ -3,15 +3,22 @@
|
|
|
3
3
|
isMenuButtonDisabled,
|
|
4
4
|
navigationStore,
|
|
5
5
|
selectedSubNavItemTitle,
|
|
6
|
+
selectedSubNavItemId,
|
|
6
7
|
} from '../stores/navigationStore.js';
|
|
7
8
|
import Logo from './Logo.svelte';
|
|
8
9
|
import MenuIcon from './icons/MenuIcon.svelte';
|
|
10
|
+
import HelpIcon from './icons/HelpIcon.svelte';
|
|
9
11
|
import { onMount } from 'svelte';
|
|
12
|
+
import { get } from 'svelte/store';
|
|
10
13
|
|
|
11
|
-
let { profileMenuData, logoLinkUrl, logoLinkLabel } =
|
|
14
|
+
let { profileMenuData, logoLinkUrl, logoLinkLabel, supplementalMenuData } =
|
|
15
|
+
$props();
|
|
12
16
|
|
|
13
17
|
import ProfileMenu from './ProfileMenu.svelte';
|
|
14
18
|
|
|
19
|
+
const helpUrl = supplementalMenuData?.help?.url?.trim();
|
|
20
|
+
const isHelpSelected = $derived(() => get(selectedSubNavItemId) === 'help');
|
|
21
|
+
|
|
15
22
|
onMount(() => {
|
|
16
23
|
// Listen for section visibility changes to update header
|
|
17
24
|
const handleSectionVisible = (event: Event) => {
|
|
@@ -67,14 +74,66 @@
|
|
|
67
74
|
}, 100);
|
|
68
75
|
}
|
|
69
76
|
|
|
77
|
+
// Detect help page and set selection state (aligned with DesktopSideNav logic)
|
|
78
|
+
const checkHelpPage = () => {
|
|
79
|
+
// Skip check for hash links - they stay on the same page
|
|
80
|
+
if (!helpUrl || helpUrl === '#' || helpUrl.startsWith('#')) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const location = (
|
|
85
|
+
globalThis as {
|
|
86
|
+
location?: { pathname?: string; origin?: string };
|
|
87
|
+
}
|
|
88
|
+
).location;
|
|
89
|
+
if (location?.origin && location?.pathname) {
|
|
90
|
+
const helpPath = getPathname(helpUrl, location.origin);
|
|
91
|
+
if (helpPath && location.pathname === helpPath) {
|
|
92
|
+
selectedSubNavItemId.set('help');
|
|
93
|
+
} else if (
|
|
94
|
+
get(selectedSubNavItemId) === 'help' &&
|
|
95
|
+
helpPath &&
|
|
96
|
+
location.pathname !== helpPath
|
|
97
|
+
) {
|
|
98
|
+
// Clear help selection if we navigated away from help page
|
|
99
|
+
selectedSubNavItemId.set(null);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
checkHelpPage();
|
|
105
|
+
|
|
106
|
+
// Also listen for popstate events (back/forward navigation)
|
|
107
|
+
window.addEventListener('popstate', checkHelpPage);
|
|
108
|
+
|
|
70
109
|
return () => {
|
|
71
110
|
window.removeEventListener('sectionVisible', handleSectionVisible);
|
|
111
|
+
window.removeEventListener('popstate', checkHelpPage);
|
|
72
112
|
};
|
|
73
113
|
});
|
|
74
114
|
|
|
115
|
+
function getPathname(url: string, baseOrigin: string) {
|
|
116
|
+
try {
|
|
117
|
+
return new URL(url, baseOrigin).pathname;
|
|
118
|
+
} catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
75
123
|
function toggleMobileNav() {
|
|
76
124
|
navigationStore.toggleExpanded();
|
|
77
125
|
}
|
|
126
|
+
|
|
127
|
+
function handleHelpClick(event: MouseEvent) {
|
|
128
|
+
selectedSubNavItemId.set('help');
|
|
129
|
+
|
|
130
|
+
// If it's a hash link, prevent default to maintain state on same page
|
|
131
|
+
if (helpUrl === '#' || helpUrl?.startsWith('#')) {
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
// State is already set above, so it will persist
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
78
137
|
</script>
|
|
79
138
|
|
|
80
139
|
<nav class="mobile-top-nav" part="mobile-top-nav">
|
|
@@ -101,6 +160,22 @@
|
|
|
101
160
|
<span class="brand-text">{$selectedSubNavItemTitle || ''}</span>
|
|
102
161
|
</div>
|
|
103
162
|
|
|
163
|
+
{#if helpUrl}
|
|
164
|
+
<a
|
|
165
|
+
class="help-button"
|
|
166
|
+
class:selected={isHelpSelected()}
|
|
167
|
+
aria-current={isHelpSelected()}
|
|
168
|
+
href={helpUrl}
|
|
169
|
+
title="Help"
|
|
170
|
+
aria-label="Help"
|
|
171
|
+
onclick={handleHelpClick}
|
|
172
|
+
>
|
|
173
|
+
<span class="icon-container">
|
|
174
|
+
<HelpIcon isSelected={isHelpSelected()} />
|
|
175
|
+
</span>
|
|
176
|
+
</a>
|
|
177
|
+
{/if}
|
|
178
|
+
|
|
104
179
|
{#if profileMenuData}
|
|
105
180
|
<ProfileMenu
|
|
106
181
|
userMeta={profileMenuData?.userMeta}
|
|
@@ -184,4 +259,28 @@
|
|
|
184
259
|
.menu-button:focus {
|
|
185
260
|
outline: none;
|
|
186
261
|
}
|
|
262
|
+
|
|
263
|
+
.help-button {
|
|
264
|
+
display: flex;
|
|
265
|
+
align-items: center;
|
|
266
|
+
justify-content: center;
|
|
267
|
+
margin-right: var(--ai-size-4);
|
|
268
|
+
text-decoration: none;
|
|
269
|
+
color: inherit;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.help-button .icon-container {
|
|
273
|
+
display: flex;
|
|
274
|
+
align-items: center;
|
|
275
|
+
justify-content: center;
|
|
276
|
+
width: var(--ai-size-40);
|
|
277
|
+
height: var(--ai-size-40);
|
|
278
|
+
border-radius: var(--ai-size-4);
|
|
279
|
+
transition: background-color var(--ai-transition-ease-fast);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.help-button:hover .icon-container,
|
|
283
|
+
.help-button.selected .icon-container {
|
|
284
|
+
background-color: var(--ai-color-steel-300);
|
|
285
|
+
}
|
|
187
286
|
</style>
|
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
import MobileTopNav from './MobileTopNav.svelte';
|
|
9
9
|
|
|
10
10
|
// Props for the web component
|
|
11
|
-
let { profileMenuData, logoLinkUrl, logoLinkLabel } =
|
|
11
|
+
let { profileMenuData, logoLinkUrl, logoLinkLabel, supplementalMenuData } =
|
|
12
|
+
$props();
|
|
12
13
|
</script>
|
|
13
14
|
|
|
14
|
-
<MobileTopNav
|
|
15
|
+
<MobileTopNav
|
|
16
|
+
{profileMenuData}
|
|
17
|
+
{logoLinkUrl}
|
|
18
|
+
{logoLinkLabel}
|
|
19
|
+
{supplementalMenuData}
|
|
20
|
+
/>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
export let
|
|
2
|
+
export let isSelected = false;
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
5
|
<svg
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
>
|
|
12
12
|
<path
|
|
13
13
|
d="M9.87891 7.51884C11.0505 6.49372 12.95 6.49372 14.1215 7.51884C15.2931 8.54397 15.2931 10.206 14.1215 11.2312C13.9176 11.4096 13.6917 11.5569 13.4513 11.6733C12.7056 12.0341 12.0002 12.6716 12.0002 13.5V14.25M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12ZM12 17.25H12.0075V17.2575H12V17.25Z"
|
|
14
|
-
stroke={
|
|
14
|
+
stroke={isSelected ? '#000' : '#585C63'}
|
|
15
15
|
stroke-width="1.5"
|
|
16
16
|
stroke-linecap="round"
|
|
17
17
|
stroke-linejoin="round"
|
|
@@ -77,6 +77,7 @@ const discover = discoverUrl || '#';
|
|
|
77
77
|
profileMenuData={profileMenuData}
|
|
78
78
|
logoLinkUrl={logoLinkUrl}
|
|
79
79
|
logoLinkLabel={logoLinkLabel}
|
|
80
|
+
{supplementalMenuData}
|
|
80
81
|
/>
|
|
81
82
|
<MobileSideMenu client:load {logoLinkUrl} {logoLinkLabel}>
|
|
82
83
|
<slot name="sub-nav" />
|
|
@@ -87,7 +88,7 @@ const discover = discoverUrl || '#';
|
|
|
87
88
|
hideDiscover={hideDiscover}
|
|
88
89
|
apiUrl={api}
|
|
89
90
|
chatUrl={chat}
|
|
90
|
-
consoleUrl={
|
|
91
|
+
consoleUrl={consoleApp}
|
|
91
92
|
discoverUrl={discover}
|
|
92
93
|
/>
|
|
93
94
|
</nav>
|