@gsa-tts/graymatter-ui 0.1.0 → 0.2.1
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/assets/images/ai-icons/chevron-up-down.svg +4 -0
- package/dist/graymatter-ui.js +4281 -0
- package/dist/graymatter-ui.umd.cjs +40 -0
- package/index.ts +1 -0
- package/package.json +9 -5
- package/src/components/Button.svelte +11 -23
- package/src/components/Button.webcomponent.svelte +44 -0
- package/src/components/DesktopHeader.svelte +30 -18
- package/src/components/DesktopHeader.webcomponent.svelte +17 -0
- package/src/components/DesktopSideNav.svelte +332 -72
- package/src/components/DesktopSideNav.webcomponent.svelte +32 -0
- package/src/components/Logo.webcomponent.svelte +26 -0
- package/src/components/MobileBottomNav.svelte +67 -15
- package/src/components/MobileBottomNav.webcomponent.svelte +18 -0
- package/src/components/MobileSideMenu.svelte +69 -14
- package/src/components/MobileSideMenu.webcomponent.svelte +11 -0
- package/src/components/MobileTopNav.svelte +137 -3
- package/src/components/MobileTopNav.webcomponent.svelte +14 -0
- package/src/index.ts +16 -0
- package/src/layouts/GlobalAppLayout.astro +24 -19
- package/src/stores/navigationStore.ts +0 -15
- package/src/styles/base/global.css +1 -2
- package/src/styles/components/globalAppLayout.css +9 -12
- package/src/styles/components/globalAppNav.css +30 -483
- package/src/utils/getAppUrls.ts +26 -0
- package/src/utils/index.ts +1 -0
- package/src/layouts/AppLayout.astro +0 -88
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<svelte:options customElement={{
|
|
2
|
+
tag: 'graymatter-desktop-header',
|
|
3
|
+
props: {
|
|
4
|
+
customHeaderText: { reflect: true, type: 'String', attribute: 'custom-header-text' }
|
|
5
|
+
}
|
|
6
|
+
}} />
|
|
7
|
+
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import DesktopHeader from './DesktopHeader.svelte';
|
|
10
|
+
|
|
11
|
+
// Props for the web component
|
|
12
|
+
let { customHeaderText = '' } = $props();
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<DesktopHeader
|
|
16
|
+
{customHeaderText}
|
|
17
|
+
/>
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* - If not provided, the navigation will default to expanded/open on SSR.
|
|
7
7
|
*/
|
|
8
8
|
import { onMount } from 'svelte';
|
|
9
|
-
import Logo from './Logo.svelte';
|
|
10
9
|
import {
|
|
11
10
|
isExpanded,
|
|
12
11
|
selectedItem,
|
|
@@ -19,8 +18,10 @@
|
|
|
19
18
|
import ConsoleIcon from './icons/ConsoleIcon.svelte';
|
|
20
19
|
import ApiIcon from './icons/ApiIcon.svelte';
|
|
21
20
|
import MenuIcon from './icons/MenuIcon.svelte';
|
|
21
|
+
import { getAppUrls } from '../utils/getAppUrls';
|
|
22
|
+
const urls = getAppUrls();
|
|
22
23
|
|
|
23
|
-
const { ssrSelectedItem = undefined, onNavToggle = undefined, onNavItemClick = undefined, onProfileClick = undefined, children } = $props();
|
|
24
|
+
const { ssrSelectedItem = undefined, onNavToggle = undefined, onNavItemClick = undefined, onProfileClick = undefined, children, apiUrl, chatUrl, consoleUrl, discoverUrl } = $props();
|
|
24
25
|
|
|
25
26
|
let hydrated = false;
|
|
26
27
|
let navContainer: HTMLDivElement;
|
|
@@ -75,22 +76,17 @@
|
|
|
75
76
|
const handleLayoutTransition = (event: Event) => {
|
|
76
77
|
const customEvent = event as CustomEvent;
|
|
77
78
|
const { isMobile } = customEvent.detail;
|
|
78
|
-
console.log('[DesktopSideNav] Layout transition detected:', { isMobile });
|
|
79
79
|
|
|
80
80
|
if (isMobile) {
|
|
81
81
|
// Switching to mobile: close navigation
|
|
82
|
-
console.log('[DesktopSideNav] Closing navigation for mobile');
|
|
83
82
|
navigationStore.setExpanded(false);
|
|
84
83
|
} else {
|
|
85
84
|
// Switching to desktop: open navigation if on non-discover page
|
|
86
85
|
const currentItem = $selectedItem;
|
|
87
|
-
console.log('[DesktopSideNav] Desktop transition - current item:', currentItem);
|
|
88
86
|
|
|
89
87
|
if (currentItem && currentItem !== 'discover') {
|
|
90
|
-
console.log('[DesktopSideNav] Opening navigation for desktop (non-discover page)');
|
|
91
88
|
navigationStore.setExpanded(true);
|
|
92
89
|
} else {
|
|
93
|
-
console.log('[DesktopSideNav] Keeping navigation closed for desktop (discover page or no selection)');
|
|
94
90
|
navigationStore.setExpanded(false);
|
|
95
91
|
}
|
|
96
92
|
}
|
|
@@ -110,13 +106,10 @@
|
|
|
110
106
|
onNavToggle?.({ expanded: $isExpanded });
|
|
111
107
|
}
|
|
112
108
|
|
|
113
|
-
function handleNavItemClick(item: NavigationItem) {
|
|
114
|
-
console.log('[DesktopSideNav] handleNavItemClick called for:', item, 'at:', Date.now());
|
|
115
|
-
|
|
109
|
+
function handleNavItemClick(item: NavigationItem) {
|
|
116
110
|
// Set navigation flag immediately to prevent header restoration
|
|
117
111
|
if (item !== 'discover' && typeof window !== 'undefined') {
|
|
118
112
|
sessionStorage.setItem('navigatingToMainNav', 'true');
|
|
119
|
-
console.log('[DesktopSideNav] Set navigation flag for:', item, 'at:', Date.now());
|
|
120
113
|
}
|
|
121
114
|
|
|
122
115
|
navigationStore.setSelectedItem(item);
|
|
@@ -139,7 +132,6 @@
|
|
|
139
132
|
const firstSection = mainContent.querySelector('h2[id], h3[id], h4[id], h5[id], h6[id]');
|
|
140
133
|
if (firstSection && firstSection.textContent) {
|
|
141
134
|
const firstSectionTitle = firstSection.textContent.trim();
|
|
142
|
-
console.log('[DesktopSideNav] Setting default header for', item, ':', firstSectionTitle);
|
|
143
135
|
selectedSubNavItemTitle.set(firstSectionTitle);
|
|
144
136
|
if (typeof window !== 'undefined') {
|
|
145
137
|
sessionStorage.setItem('subNav-selectedTitle', JSON.stringify(firstSectionTitle));
|
|
@@ -185,9 +177,10 @@
|
|
|
185
177
|
class="side-nav-container"
|
|
186
178
|
class:expanded={sideNavExpanded()}
|
|
187
179
|
bind:this={navContainer}
|
|
180
|
+
part="side-nav-container"
|
|
188
181
|
>
|
|
189
182
|
<div class="nav-content">
|
|
190
|
-
<div class="nav-main">
|
|
183
|
+
<div class="nav-main" part="nav-main">
|
|
191
184
|
<div class="menu-section">
|
|
192
185
|
<button
|
|
193
186
|
class="menu-button"
|
|
@@ -196,33 +189,35 @@
|
|
|
196
189
|
onclick={toggleNav}
|
|
197
190
|
onmouseenter={() => (menuButtonHovered = true)}
|
|
198
191
|
onmouseleave={() => (menuButtonHovered = false)}
|
|
199
|
-
|
|
192
|
+
onfocus={() => (menuButtonHovered = true)}
|
|
193
|
+
onblur={() => (menuButtonHovered = false)}
|
|
194
|
+
aria-label={sideNavExpanded() ? 'Close navigation menu' : 'Open navigation menu'}
|
|
195
|
+
aria-expanded={sideNavExpanded() ? 'true' : 'false'}
|
|
200
196
|
>
|
|
201
|
-
<span class="sr-only">Open navigation menu</span>
|
|
202
197
|
<div class="icon-container">
|
|
203
198
|
<div class="icon-wrapper">
|
|
204
199
|
<MenuIcon
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
200
|
+
isHovered={menuBtnHovered()}
|
|
201
|
+
isDisabled={menuBtnDisabled()}
|
|
202
|
+
isOpen={menuBtnOpen()}
|
|
203
|
+
/>
|
|
209
204
|
</div>
|
|
210
205
|
</div>
|
|
211
206
|
</button>
|
|
212
207
|
</div>
|
|
213
208
|
|
|
214
|
-
<div class="nav-items">
|
|
209
|
+
<div class="nav-items" part="nav-items">
|
|
215
210
|
<a
|
|
216
|
-
href=
|
|
211
|
+
href={discoverUrl || urls.discover}
|
|
217
212
|
class="nav-item discover-item"
|
|
218
213
|
class:selected={isNavSelected('discover')}
|
|
219
214
|
class:hovered={isNavHovered('discover')}
|
|
220
|
-
role="button"
|
|
221
|
-
tabindex="0"
|
|
222
215
|
onclick={() => handleNavItemClick('discover')}
|
|
223
216
|
onkeydown={e => handleKeyDown(e, 'discover')}
|
|
224
217
|
onmouseenter={() => (hoveredItem = 'discover')}
|
|
225
218
|
onmouseleave={() => (hoveredItem = null)}
|
|
219
|
+
aria-current={isNavSelected('discover') ? 'page' : undefined}
|
|
220
|
+
part="discover-item"
|
|
226
221
|
>
|
|
227
222
|
<div class="icon-container">
|
|
228
223
|
<div class="icon-wrapper">
|
|
@@ -232,16 +227,16 @@
|
|
|
232
227
|
<span class="nav-text">Discover</span>
|
|
233
228
|
</a>
|
|
234
229
|
<a
|
|
235
|
-
href=
|
|
230
|
+
href={chatUrl || urls.chat}
|
|
236
231
|
class="nav-item chat-item"
|
|
237
232
|
class:selected={isNavSelected('chat')}
|
|
238
233
|
class:hovered={isNavHovered('chat')}
|
|
239
|
-
role="button"
|
|
240
|
-
tabindex="0"
|
|
241
234
|
onclick={() => handleNavItemClick('chat')}
|
|
242
235
|
onkeydown={e => handleKeyDown(e, 'chat')}
|
|
243
236
|
onmouseenter={() => (hoveredItem = 'chat')}
|
|
244
237
|
onmouseleave={() => (hoveredItem = null)}
|
|
238
|
+
aria-current={isNavSelected('chat') ? 'page' : undefined}
|
|
239
|
+
part="chat-item"
|
|
245
240
|
>
|
|
246
241
|
<div class="icon-container">
|
|
247
242
|
<div class="icon-wrapper">
|
|
@@ -252,16 +247,16 @@
|
|
|
252
247
|
</a>
|
|
253
248
|
|
|
254
249
|
<a
|
|
255
|
-
href=
|
|
250
|
+
href={consoleUrl || urls.console}
|
|
256
251
|
class="nav-item console-item"
|
|
257
252
|
class:selected={isNavSelected('console')}
|
|
258
253
|
class:hovered={isNavHovered('console')}
|
|
259
|
-
role="button"
|
|
260
|
-
tabindex="0"
|
|
261
254
|
onclick={() => handleNavItemClick('console')}
|
|
262
255
|
onkeydown={e => handleKeyDown(e, 'console')}
|
|
263
256
|
onmouseenter={() => (hoveredItem = 'console')}
|
|
264
257
|
onmouseleave={() => (hoveredItem = null)}
|
|
258
|
+
aria-current={isNavSelected('console') ? 'page' : undefined}
|
|
259
|
+
part="console-item"
|
|
265
260
|
>
|
|
266
261
|
<div class="icon-container">
|
|
267
262
|
<div class="icon-wrapper">
|
|
@@ -272,16 +267,16 @@
|
|
|
272
267
|
</a>
|
|
273
268
|
|
|
274
269
|
<a
|
|
275
|
-
href=
|
|
270
|
+
href={apiUrl || urls.api}
|
|
276
271
|
class="nav-item api-item"
|
|
277
272
|
class:selected={isNavSelected('api')}
|
|
278
273
|
class:hovered={isNavHovered('api')}
|
|
279
|
-
role="button"
|
|
280
|
-
tabindex="0"
|
|
281
274
|
onclick={() => handleNavItemClick('api')}
|
|
282
275
|
onkeydown={e => handleKeyDown(e, 'api')}
|
|
283
276
|
onmouseenter={() => (hoveredItem = 'api')}
|
|
284
277
|
onmouseleave={() => (hoveredItem = null)}
|
|
278
|
+
aria-current={isNavSelected('api') ? 'page' : undefined}
|
|
279
|
+
part="api-item"
|
|
285
280
|
>
|
|
286
281
|
<div class="icon-container">
|
|
287
282
|
<div class="icon-wrapper">
|
|
@@ -293,7 +288,7 @@
|
|
|
293
288
|
</div>
|
|
294
289
|
</div>
|
|
295
290
|
|
|
296
|
-
<div class="nav-footer">
|
|
291
|
+
<div class="nav-footer" part="nav-footer">
|
|
297
292
|
<button
|
|
298
293
|
class="user-profile-button"
|
|
299
294
|
tabindex="0"
|
|
@@ -306,7 +301,7 @@
|
|
|
306
301
|
}}
|
|
307
302
|
>
|
|
308
303
|
<div class="user-profile-container">
|
|
309
|
-
<div class="user-profile-icon">
|
|
304
|
+
<div class="user-profile-icon" part="user-profile-icon">
|
|
310
305
|
<span class="user-initials">ZW</span>
|
|
311
306
|
</div>
|
|
312
307
|
</div>
|
|
@@ -314,62 +309,327 @@
|
|
|
314
309
|
</div>
|
|
315
310
|
</div>
|
|
316
311
|
|
|
317
|
-
<div class="expanded-content drawer-anim" class:open={sideNavExpanded()}>
|
|
318
|
-
|
|
319
|
-
<div class="
|
|
320
|
-
<div class="logo-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
</div>
|
|
325
|
-
</div>
|
|
326
|
-
</div>
|
|
312
|
+
<div class="expanded-content drawer-anim" class:open={sideNavExpanded()} part="expanded-content">
|
|
313
|
+
{#if sideNavExpanded()}
|
|
314
|
+
<div class="drawer-content" part="drawer-content">
|
|
315
|
+
<div class="logo-placeholder"></div>
|
|
316
|
+
<nav aria-label="Sub navigation">
|
|
317
|
+
{@render children?.()}
|
|
318
|
+
</nav>
|
|
327
319
|
</div>
|
|
328
|
-
|
|
329
|
-
{@render children?.()}
|
|
330
|
-
</nav>
|
|
331
|
-
</div>
|
|
320
|
+
{/if}
|
|
332
321
|
</div>
|
|
333
322
|
</div>
|
|
334
323
|
|
|
335
324
|
<style>
|
|
336
325
|
.expanded-content.drawer-anim {
|
|
337
|
-
width: 0;
|
|
338
|
-
min-width: 0;
|
|
339
326
|
max-width: 0;
|
|
340
327
|
overflow: hidden;
|
|
341
|
-
opacity: 0.7;
|
|
342
328
|
pointer-events: none;
|
|
343
|
-
transition:
|
|
344
|
-
|
|
345
|
-
min-width 0.4s cubic-bezier(.4,0,.2,1),
|
|
346
|
-
max-width 0.4s cubic-bezier(.4,0,.2,1),
|
|
347
|
-
opacity 0.2s;
|
|
329
|
+
transition:
|
|
330
|
+
max-width 0.2s cubic-bezier(.4, 0, .2, 1);
|
|
348
331
|
}
|
|
332
|
+
|
|
349
333
|
.expanded-content.drawer-anim.open {
|
|
350
|
-
width: 12.5rem;
|
|
351
|
-
min-width: 12.5rem;
|
|
352
334
|
max-width: 12.5rem;
|
|
353
|
-
opacity: 1;
|
|
354
335
|
pointer-events: auto;
|
|
355
336
|
}
|
|
337
|
+
|
|
356
338
|
.drawer-content {
|
|
339
|
+
width: 12.5rem;
|
|
340
|
+
height: 100%;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.logo-placeholder {
|
|
344
|
+
height: var(--ai-size-72);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.user-profile-container,
|
|
348
|
+
.user-profile-icon {
|
|
349
|
+
display: flex;
|
|
350
|
+
align-items: center;
|
|
351
|
+
justify-content: center;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.menu-button {
|
|
355
|
+
display: flex;
|
|
356
|
+
align-items: center;
|
|
357
|
+
justify-content: center;
|
|
358
|
+
border: none;
|
|
359
|
+
background: none;
|
|
360
|
+
cursor: pointer;
|
|
361
|
+
border-radius: var(--ai-size-8);
|
|
362
|
+
transition: background-color 0.2s ease;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.menu-button:disabled,
|
|
366
|
+
.menu-button.disabled {
|
|
367
|
+
cursor: not-allowed;
|
|
368
|
+
opacity: 0.5;
|
|
369
|
+
background-color: transparent;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.user-profile-icon {
|
|
373
|
+
border-radius: var(--ai-size-6);
|
|
374
|
+
background: var(--ai-color-steel-700);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.user-initials {
|
|
378
|
+
color: var(--ai-color-white);
|
|
379
|
+
text-align: center;
|
|
380
|
+
font-weight: 400;
|
|
381
|
+
line-height: 1.3;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.side-nav-container {
|
|
385
|
+
display: flex;
|
|
386
|
+
flex-shrink: 0;
|
|
387
|
+
position: relative;
|
|
388
|
+
z-index: var(--ai-layer-2);
|
|
389
|
+
height: 100%;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.side-nav-container.expanded {
|
|
393
|
+
width: 16.875rem;
|
|
394
|
+
min-width: 12.5rem;
|
|
395
|
+
max-width: 16.875rem;
|
|
396
|
+
height: 100%;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.expanded-content {
|
|
400
|
+
display: flex;
|
|
401
|
+
width: 12.5rem;
|
|
402
|
+
opacity: 1;
|
|
403
|
+
flex: none;
|
|
404
|
+
height: 100%;
|
|
405
|
+
background: var(--ai-color-steel-100);
|
|
406
|
+
border-right: 0.0625rem solid var(--ai-color-steel-100);
|
|
407
|
+
overflow: hidden;
|
|
408
|
+
flex-direction: column;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.side-nav-container.expanded .expanded-content {
|
|
412
|
+
width: 12.5rem;
|
|
413
|
+
opacity: 1;
|
|
414
|
+
overflow-y: auto;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.side-nav-container:not(.expanded) .expanded-content {
|
|
418
|
+
width: 0;
|
|
357
419
|
opacity: 0;
|
|
358
|
-
transform: translateX(-10px);
|
|
359
|
-
transition:
|
|
360
|
-
opacity 0.4s 0.20s cubic-bezier(.4,0,.2,1),
|
|
361
|
-
transform 0.4s 0.20s cubic-bezier(.4,0,.2,1);
|
|
362
420
|
}
|
|
363
|
-
|
|
421
|
+
|
|
422
|
+
.nav-content {
|
|
423
|
+
display: flex;
|
|
424
|
+
width: var(--ai-size-72);
|
|
425
|
+
height: 100%;
|
|
426
|
+
padding-bottom: var(--ai-size-16);
|
|
427
|
+
flex-direction: column;
|
|
428
|
+
align-items: flex-start;
|
|
429
|
+
gap: var(--ai-size-4);
|
|
430
|
+
flex: none;
|
|
431
|
+
background: var(--ai-color-steel-200);
|
|
432
|
+
border-right: 0.0625rem solid var(--ai-color-steel-200);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.nav-main {
|
|
436
|
+
display: flex;
|
|
437
|
+
flex-direction: column;
|
|
438
|
+
align-items: flex-start;
|
|
439
|
+
gap: var(--ai-size-4);
|
|
440
|
+
flex: 1 0 0;
|
|
441
|
+
align-self: stretch;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.nav-footer {
|
|
445
|
+
display: flex;
|
|
446
|
+
padding: var(--ai-size-8) var(--ai-size-4);
|
|
447
|
+
flex-direction: column;
|
|
448
|
+
justify-content: center;
|
|
449
|
+
align-items: center;
|
|
450
|
+
gap: var(--ai-size-4);
|
|
451
|
+
align-self: stretch;
|
|
452
|
+
margin-top: auto;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.user-profile-button {
|
|
456
|
+
background: none;
|
|
457
|
+
border: none;
|
|
458
|
+
padding: 0;
|
|
459
|
+
cursor: pointer;
|
|
460
|
+
display: flex;
|
|
461
|
+
justify-content: center;
|
|
462
|
+
align-items: center;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.user-profile-button:focus {
|
|
466
|
+
outline: var(--ai-size-2) solid var(--ai-color-blue-600);
|
|
467
|
+
outline-offset: var(--ai-size-2);
|
|
468
|
+
border-radius: var(--ai-size-4);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.user-profile-container {
|
|
472
|
+
width: var(--ai-size-40);
|
|
473
|
+
height: var(--ai-size-40);
|
|
474
|
+
aspect-ratio: 1/1;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.user-profile-icon {
|
|
478
|
+
padding: 0.5556rem 0.4931rem 0.5694rem 0.3819rem;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.user-initials {
|
|
482
|
+
font-size: var(--ai-size-16);
|
|
483
|
+
font-style: normal;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.menu-section {
|
|
487
|
+
display: flex;
|
|
488
|
+
padding: var(--ai-size-4);
|
|
489
|
+
justify-content: center;
|
|
490
|
+
align-items: center;
|
|
491
|
+
align-self: stretch;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.menu-button {
|
|
495
|
+
display: flex;
|
|
496
|
+
padding: var(--ai-size-4);
|
|
497
|
+
justify-content: center;
|
|
498
|
+
align-items: center;
|
|
499
|
+
background: none;
|
|
500
|
+
border: none;
|
|
501
|
+
cursor: pointer;
|
|
364
502
|
opacity: 1;
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
503
|
+
transition: opacity 0.2s ease;
|
|
504
|
+
will-change: opacity;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.menu-button.disabled {
|
|
508
|
+
cursor: not-allowed;
|
|
509
|
+
opacity: 0.5;
|
|
510
|
+
will-change: opacity;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.menu-button:focus,
|
|
514
|
+
.nav-item:focus {
|
|
515
|
+
outline: none;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.menu-button:focus .icon-container,
|
|
519
|
+
.nav-item:focus .icon-container {
|
|
520
|
+
outline: var(--ai-size-2) solid var(--ai-color-blue-600);
|
|
521
|
+
outline-offset: var(--ai-size-2);
|
|
522
|
+
border-radius: var(--ai-size-4);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.nav-items {
|
|
526
|
+
display: flex;
|
|
527
|
+
width: var(--ai-size-72);
|
|
528
|
+
flex-direction: column;
|
|
529
|
+
align-items: flex-start;
|
|
530
|
+
gap: var(--ai-size-4);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.nav-item {
|
|
534
|
+
display: flex;
|
|
535
|
+
height: 4.125rem;
|
|
536
|
+
padding: var(--ai-size-4);
|
|
537
|
+
flex-direction: column;
|
|
538
|
+
justify-content: center;
|
|
539
|
+
align-items: center;
|
|
540
|
+
gap: var(--ai-size-2);
|
|
541
|
+
align-self: stretch;
|
|
542
|
+
cursor: pointer;
|
|
543
|
+
text-decoration: none;
|
|
544
|
+
color: inherit;
|
|
545
|
+
position: relative;
|
|
546
|
+
flex-shrink: 0;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
.icon-container {
|
|
550
|
+
display: flex;
|
|
551
|
+
width: var(--ai-size-40);
|
|
552
|
+
height: var(--ai-size-40);
|
|
553
|
+
padding: var(--ai-size-8);
|
|
554
|
+
justify-content: center;
|
|
555
|
+
align-items: center;
|
|
556
|
+
flex-shrink: 0;
|
|
557
|
+
position: relative;
|
|
558
|
+
contain: layout style;
|
|
559
|
+
transition: background-color 0.3s ease,
|
|
560
|
+
border-radius 0.3s ease;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
.icon-wrapper {
|
|
564
|
+
display: flex;
|
|
565
|
+
width: var(--ai-size-28);
|
|
566
|
+
height: var(--ai-size-28);
|
|
567
|
+
justify-content: center;
|
|
568
|
+
align-items: center;
|
|
569
|
+
flex-shrink: 0;
|
|
570
|
+
aspect-ratio: 1/1;
|
|
571
|
+
position: relative;
|
|
572
|
+
overflow: hidden;
|
|
573
|
+
transition: transform 0.3s ease;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
.icon-wrapper :global(svg) {
|
|
577
|
+
width: var(--ai-size-24);
|
|
578
|
+
height: var(--ai-size-24);
|
|
579
|
+
flex-shrink: 0;
|
|
580
|
+
position: absolute;
|
|
581
|
+
top: 50%;
|
|
582
|
+
left: 50%;
|
|
583
|
+
transform: translate(-50%, -50%);
|
|
584
|
+
transition: all 0.3s ease;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
.icon-wrapper :global(svg path) {
|
|
588
|
+
stroke-width: 1.5;
|
|
589
|
+
vector-effect: non-scaling-stroke;
|
|
590
|
+
transition: stroke 0.3s ease,
|
|
591
|
+
fill 0.3s ease,
|
|
592
|
+
stroke-width 0.3s ease;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.nav-text {
|
|
596
|
+
font-size: var(--ai-size-12);
|
|
597
|
+
text-align: center;
|
|
598
|
+
color: var(--ai-color-neutral-900);
|
|
599
|
+
line-height: 1.3;
|
|
369
600
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
601
|
+
|
|
602
|
+
.menu-button.disabled:hover .icon-container,
|
|
603
|
+
.menu-button:disabled:hover .icon-container {
|
|
604
|
+
background: none !important;
|
|
605
|
+
border-radius: var(--ai-size-4);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.nav-item.hovered .icon-container,
|
|
609
|
+
.nav-item:active .icon-container,
|
|
610
|
+
.nav-item.selected .icon-container,
|
|
611
|
+
.nav-item.selected.hovered .icon-container,
|
|
612
|
+
.menu-button:hover .icon-container,
|
|
613
|
+
.menu-button:active .icon-container {
|
|
614
|
+
background-color: var(--ai-color-steel-300);
|
|
615
|
+
border-radius: var(--ai-size-4);
|
|
374
616
|
}
|
|
617
|
+
|
|
618
|
+
.nav-item {
|
|
619
|
+
flex: 1;
|
|
620
|
+
display: flex;
|
|
621
|
+
flex-direction: column;
|
|
622
|
+
align-items: center;
|
|
623
|
+
justify-content: center;
|
|
624
|
+
padding: var(--ai-size-4);
|
|
625
|
+
text-decoration: none;
|
|
626
|
+
color: var(--ai-color-neutral-600);
|
|
627
|
+
transition: color 0.2s ease;
|
|
628
|
+
height: 100%;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
.nav-item:hover {
|
|
632
|
+
color: var(--ai-color-neutral-700);
|
|
633
|
+
}
|
|
634
|
+
|
|
375
635
|
</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<svelte:options customElement={{
|
|
2
|
+
tag: 'graymatter-desktop-side-nav'
|
|
3
|
+
}} />
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import DesktopSideNav from './DesktopSideNav.svelte';
|
|
7
|
+
|
|
8
|
+
// Props for the web component
|
|
9
|
+
let {
|
|
10
|
+
ssrSelectedItem,
|
|
11
|
+
onNavToggle,
|
|
12
|
+
onNavItemClick,
|
|
13
|
+
onProfileClick,
|
|
14
|
+
apiUrl,
|
|
15
|
+
chatUrl,
|
|
16
|
+
consoleUrl,
|
|
17
|
+
discoverUrl
|
|
18
|
+
} = $props();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<DesktopSideNav
|
|
22
|
+
{ssrSelectedItem}
|
|
23
|
+
{onNavToggle}
|
|
24
|
+
{onNavItemClick}
|
|
25
|
+
{onProfileClick}
|
|
26
|
+
{apiUrl}
|
|
27
|
+
{chatUrl}
|
|
28
|
+
{consoleUrl}
|
|
29
|
+
{discoverUrl}
|
|
30
|
+
>
|
|
31
|
+
<slot />
|
|
32
|
+
</DesktopSideNav>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<svelte:options customElement={{
|
|
2
|
+
tag: 'graymatter-logo',
|
|
3
|
+
props: {
|
|
4
|
+
isInverted: { reflect: true, type: 'Boolean', attribute: 'is-inverted' },
|
|
5
|
+
width: { reflect: true, type: 'Number', attribute: 'width' },
|
|
6
|
+
height: { reflect: true, type: 'Number', attribute: 'height' }
|
|
7
|
+
}
|
|
8
|
+
}} />
|
|
9
|
+
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import Logo from './Logo.svelte';
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
isInverted = false,
|
|
15
|
+
width = undefined,
|
|
16
|
+
height = undefined,
|
|
17
|
+
...props
|
|
18
|
+
} = $props();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<Logo
|
|
22
|
+
{isInverted}
|
|
23
|
+
{width}
|
|
24
|
+
{height}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|