Skip to content

Commit b0df11c

Browse files
authored
UserMenu refactoring (#2374)
* Refactor out user menu to it's own component with menu slot * Updated user menu * Smaller gaps * Remove py-2 to keep icons nice and square * Consistent disabled class * Add tooltip to Namespace switcher. Make bottom namespace nav items better * Remove tooltip from mobile nav * Move back navigation item css
1 parent 17398e7 commit b0df11c

15 files changed

+154
-101
lines changed

pnpm-lock.yaml

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/components/bottom-nav-links.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
{#if open}
1010
<div
11-
class="flex h-full flex-col flex-col-reverse justify-start gap-8 overflow-auto px-4 py-8"
11+
class="flex h-full flex-col flex-col-reverse justify-start gap-6 overflow-auto px-4 py-8"
1212
>
1313
{#each linkList as item}
1414
{#if item.divider}

src/lib/components/bottom-nav-namespaces.svelte

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script lang="ts">
22
import Input from '$lib/holocene/input/input.svelte';
3+
import { lastUsedNamespace } from '$lib/stores/namespaces';
34
import type { NamespaceListItem } from '$lib/types/global';
45
56
export let open = false;
@@ -30,11 +31,22 @@
3031
/>
3132
{#each namespaces as { namespace, onClick }}
3233
<button
33-
class="w-full text-left"
34+
class="namespace"
35+
class:selected={namespace === $lastUsedNamespace}
3436
on:click|preventDefault|stopPropagation={() => onClick(namespace)}
3537
>
3638
{namespace}
3739
</button>
3840
{/each}
3941
</div>
4042
{/if}
43+
44+
<style lang="postcss">
45+
.namespace {
46+
@apply w-full cursor-pointer rounded border border-transparent text-left text-sm font-medium hover:surface-interactive-secondary focus-visible:surface-interactive-secondary focus-visible:border-inverse focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-primary/70 dark:focus-visible:border-interactive;
47+
48+
&.selected {
49+
@apply text-brand;
50+
}
51+
}
52+
</style>

src/lib/components/bottom-nav-settings.svelte

+2-22
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@
44
import DataEncoderSettings from '$lib/components/data-encoder-settings.svelte';
55
import TimezoneSelect from '$lib/components/timezone-select.svelte';
66
import NavigationButton from '$lib/holocene/navigation/navigation-button.svelte';
7-
import NavigationItem from '$lib/holocene/navigation/navigation-item.svelte';
87
import { translate } from '$lib/i18n/translate';
9-
import { authUser } from '$lib/stores/auth-user';
108
import { dataEncoder } from '$lib/stores/data-encoder';
119
import { useDarkMode } from '$lib/utilities/dark-mode';
1210
1311
import { viewDataEncoderSettings } from './data-encoder-settings.svelte';
1412
1513
export let open = false;
16-
export let logout: () => void;
17-
export let userEmaiLink = '';
1814
1915
$: hasCodecServer = $dataEncoder?.endpoint;
2016
@@ -28,7 +24,7 @@
2824
</script>
2925

3026
{#if open}
31-
<div class="flex h-full flex-col justify-end gap-8 overflow-auto px-4 py-8">
27+
<div class="flex h-full flex-col justify-end gap-6 overflow-auto px-4 py-8">
3228
<TimezoneSelect position="left" />
3329
{#if $dataEncoder.hasError}
3430
<p class="text-red-400">{translate('data-encoder.codec-server-error')}</p>
@@ -49,22 +45,6 @@
4945
label={$useDarkMode ? translate('common.night') : translate('common.day')}
5046
icon={$useDarkMode ? 'moon' : 'sun'}
5147
/>
52-
{#if $authUser.accessToken}
53-
<div class="border-b-2 border-subtle" />
54-
<NavigationItem
55-
link={userEmaiLink}
56-
disabled={!userEmaiLink}
57-
tooltip={$authUser.email}
58-
label={$authUser.email}
59-
data-testid="email"
60-
/>
61-
<NavigationButton
62-
onClick={logout}
63-
tooltip={translate('common.log-out')}
64-
label={translate('common.log-out')}
65-
icon="exit"
66-
data-testid="log-out"
67-
/>
68-
{/if}
48+
<slot />
6949
</div>
7050
{/if}

src/lib/components/bottom-nav.svelte

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919
import BottomNavNamespaces from './bottom-nav-namespaces.svelte';
2020
import BottomNavSettings from './bottom-nav-settings.svelte';
2121
22-
export let logout: () => void;
2322
export let namespaceList: NamespaceListItem[] = [];
24-
export let userEmaiLink = '';
2523
export let linkList: NavLinkListItem[];
2624
export let isCloud = false;
2725
@@ -85,7 +83,9 @@
8583
>
8684
<BottomNavLinks open={viewLinks} {linkList} />
8785
<BottomNavNamespaces open={viewNamespaces} {namespaceList} />
88-
<BottomNavSettings open={viewSettings} {logout} {userEmaiLink} />
86+
<BottomNavSettings open={viewSettings}>
87+
<slot />
88+
</BottomNavSettings>
8989
</div>
9090
{/if}
9191
<nav

src/lib/components/top-nav.svelte

+2-45
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,13 @@
55
import TimezoneSelect from '$lib/components/timezone-select.svelte';
66
import Button from '$lib/holocene/button.svelte';
77
import Combobox from '$lib/holocene/combobox/combobox.svelte';
8-
import {
9-
Menu,
10-
MenuButton,
11-
MenuContainer,
12-
MenuItem,
13-
} from '$lib/holocene/menu';
148
import { translate } from '$lib/i18n/translate';
15-
import { authUser } from '$lib/stores/auth-user';
169
import { dataEncoder } from '$lib/stores/data-encoder';
1710
import { lastUsedNamespace } from '$lib/stores/namespaces';
1811
import type { NamespaceListItem } from '$lib/types/global';
1912
import { routeForNamespace } from '$lib/utilities/route-for';
2013
21-
export let logout: () => void;
2214
export let namespaceList: NamespaceListItem[] = [];
23-
export let userEmaiLink = '';
2415
2516
let screenWidth: number;
2617
@@ -37,12 +28,6 @@
3728
(namespaceListItem) => namespaceListItem.namespace === namespace,
3829
);
3930
40-
let showProfilePic = true;
41-
42-
function fixImage() {
43-
showProfilePic = false;
44-
}
45-
4631
const handleNamespaceSelect = (
4732
event: CustomEvent<{ value: NamespaceListItem }>,
4833
) => {
@@ -53,7 +38,6 @@
5338
</script>
5439

5540
<svelte:window bind:innerWidth={screenWidth} />
56-
5741
<nav
5842
class="surface-primary sticky top-0 z-40 flex hidden w-full flex-col items-center justify-end border-b border-subtle p-1 px-4 md:flex md:flex-row md:px-8"
5943
data-testid="top-nav"
@@ -73,6 +57,7 @@
7357
optionValueKey="namespace"
7458
on:change={handleNamespaceSelect}
7559
minSize={32}
60+
actionTooltip={translate('namespaces.go-to-namespace')}
7661
>
7762
<Button
7863
slot="action"
@@ -87,34 +72,6 @@
8772
<div class="flex items-center gap-2">
8873
<TimezoneSelect position={screenWidth < 768 ? 'left' : 'right'} />
8974
<DataEncoderStatus />
90-
{#if $authUser.accessToken}
91-
<MenuContainer>
92-
<MenuButton variant="ghost" hasIndicator controls="user-menu">
93-
<img
94-
src={$authUser?.picture}
95-
alt={$authUser?.profile ?? translate('common.user-profile')}
96-
class="h-[24px] w-[24px] cursor-pointer rounded-md"
97-
on:error={fixImage}
98-
class:hidden={!showProfilePic}
99-
/>
100-
<div
101-
class="aspect-square h-full w-[24px] rounded-md bg-blue-200 p-0.5"
102-
class:hidden={showProfilePic}
103-
>
104-
{#if $authUser?.name}
105-
<div class="text-center text-sm text-black">
106-
{$authUser?.name.trim().charAt(0)}
107-
</div>
108-
{/if}
109-
</div>
110-
</MenuButton>
111-
<Menu id="user-menu" position="right">
112-
<MenuItem href={userEmaiLink} disabled={!userEmaiLink}>
113-
{$authUser.email}
114-
</MenuItem>
115-
<MenuItem on:click={logout}>{translate('common.log-out')}</MenuItem>
116-
</Menu>
117-
</MenuContainer>
118-
{/if}
75+
<slot />
11976
</div>
12077
</nav>

src/lib/holocene/combobox/combobox.svelte

+11-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import type { IconName } from '../icon';
1616
import Icon from '../icon/icon.svelte';
1717
import MenuDivider from '../menu/menu-divider.svelte';
18+
import Tooltip from '../tooltip.svelte';
1819
1920
type T = $$Generic;
2021
@@ -44,6 +45,7 @@
4445
'data-testid'?: string;
4546
error?: string;
4647
valid?: boolean;
48+
actionTooltip?: string;
4749
}
4850
4951
type MultiSelectProps = {
@@ -108,6 +110,8 @@
108110
export let selectAllLabel = 'Select All';
109111
export let deselectAllLabel = 'Deselect All';
110112
export let removeChipLabel = 'Remove Option';
113+
export let actionTooltip = '';
114+
111115
export let numberOfItemsSelectedLabel = (count: number) =>
112116
`${count} option${count > 1 ? 's' : ''} selected`;
113117
@@ -392,7 +396,13 @@
392396
</div>
393397
{#if $$slots.action}
394398
<div class="ml-1 flex h-full items-center border-l-2 border-subtle p-0.5">
395-
<slot name="action" />
399+
{#if actionTooltip}
400+
<Tooltip text={actionTooltip} right>
401+
<slot name="action" />
402+
</Tooltip>
403+
{:else}
404+
<slot name="action" />
405+
{/if}
396406
</div>
397407
{/if}
398408
</div>

src/lib/holocene/menu/menu-item.svelte

+1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
class:destructive
138138
class:disabled
139139
class:selected
140+
class:hoverable
140141
aria-hidden={disabled ? 'true' : 'false'}
141142
aria-disabled={disabled}
142143
tabindex={disabled ? -1 : 0}

src/lib/holocene/navigation/navigation-button.svelte

+16-8
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
44
import Icon from '../icon/icon.svelte';
55
6-
export let onClick: () => void;
6+
export let onClick: () => void = () => {};
77
export let label: string;
88
export let icon: IconName | undefined = undefined;
99
export let tooltip = label;
1010
export let animate = false;
1111
export let active = false;
12+
export let disabled = false;
1213
</script>
1314

1415
<div
@@ -17,17 +18,24 @@
1718
on:keypress={onClick}
1819
tabindex="0"
1920
data-testid={$$props['data-testid']}
21+
class:disabled
2022
class="relative mb-1 flex items-center whitespace-nowrap rounded-lg p-1 pl-2 text-sm font-medium hover:bg-white hover:text-black group-[.surface-primary]:hover:bg-black group-[.surface-primary]:hover:text-white group-[.surface-primary]:dark:hover:bg-white group-[.surface-primary]:dark:hover:text-black"
2123
>
22-
<div
23-
class="flex h-6 w-6 items-center after:absolute after:left-[calc(100%_+_1.5rem)] after:top-0 after:hidden after:h-8 after:items-center after:rounded-md after:bg-slate-800 after:p-1 after:px-2 after:text-xs after:text-white after:content-[attr(data-tooltip)] group-data-[nav=closed]:hover:after:flex"
24-
data-tooltip={tooltip}
25-
>
26-
{#if icon}
24+
{#if icon}
25+
<div
26+
class="flex h-6 w-6 items-center after:absolute after:left-[calc(100%_+_1.5rem)] after:top-0 after:hidden after:h-8 after:items-center after:rounded-md after:bg-slate-800 after:p-1 after:px-2 after:text-xs after:text-white after:content-[attr(data-tooltip)] group-data-[nav=closed]:hover:after:flex"
27+
data-tooltip={tooltip}
28+
>
2729
<Icon name={icon} {animate} {active} />
28-
{/if}
29-
</div>
30+
</div>
31+
{/if}
3032
<div class="opacity-0 transition-opacity group-data-[nav=open]:opacity-100">
3133
{label}
3234
</div>
3335
</div>
36+
37+
<style lang="postcss">
38+
.disabled {
39+
@apply pointer-events-none cursor-not-allowed text-subtle;
40+
}
41+
</style>

src/lib/holocene/navigation/navigation-item.svelte

+11-11
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@
3737
class="mb-1 flex items-center whitespace-nowrap rounded-lg p-1 pl-2 text-sm font-medium"
3838
class:text-disabled={disabled}
3939
>
40-
<div
41-
class="flex h-6 w-6 items-center after:absolute after:left-[calc(100%_+_1.5rem)] after:top-0 after:hidden after:h-8 after:items-center after:rounded-md after:bg-slate-800 after:p-1 after:px-2 after:text-xs after:text-white after:content-[attr(data-tooltip)] group-data-[nav=closed]:hover:after:flex"
42-
data-tooltip={tooltip}
43-
>
44-
{#if icon}
40+
{#if icon}
41+
<div
42+
class="flex h-6 w-6 items-center after:absolute after:left-[calc(100%_+_1.5rem)] after:top-0 after:hidden after:h-8 after:items-center after:rounded-md after:bg-slate-800 after:p-1 after:px-2 after:text-xs after:text-white after:content-[attr(data-tooltip)] group-data-[nav=closed]:hover:after:flex"
43+
data-tooltip={tooltip}
44+
>
4545
<Icon name={icon} {animate} />
46-
{/if}
47-
</div>
46+
</div>
47+
{/if}
4848
<div
4949
class="opacity-0 transition-opacity group-data-[nav=open]:opacity-100"
5050
class:pointer-events-none={!$navOpen}
@@ -55,12 +55,12 @@
5555
</div>
5656

5757
<style lang="postcss">
58-
a.disabled {
59-
@apply pointer-events-none cursor-not-allowed opacity-50;
60-
}
61-
6258
a:hover,
6359
a.active {
6460
@apply bg-white text-black group-[.surface-primary]:bg-black group-[.surface-primary]:text-white group-[.surface-primary]:dark:bg-white group-[.surface-primary]:dark:text-black;
6561
}
62+
63+
a.disabled {
64+
@apply pointer-events-none cursor-not-allowed text-subtle;
65+
}
6666
</style>
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script lang="ts">
2+
import NavigationButton from '$lib/holocene/navigation/navigation-button.svelte';
3+
import { translate } from '$lib/i18n/translate';
4+
import { authUser } from '$lib/stores/auth-user';
5+
6+
export let logout: () => void;
7+
</script>
8+
9+
{#if $authUser.accessToken}
10+
<div class="border-b-2 border-subtle" />
11+
<NavigationButton
12+
tooltip={$authUser.email}
13+
label={$authUser.email}
14+
icon="astronaut"
15+
data-testid="email"
16+
disabled
17+
/>
18+
<NavigationButton
19+
onClick={logout}
20+
tooltip={translate('common.log-out')}
21+
label={translate('common.log-out')}
22+
icon="exit"
23+
data-testid="log-out"
24+
/>
25+
{/if}

0 commit comments

Comments
 (0)