173 lines
4.9 KiB
Svelte
173 lines
4.9 KiB
Svelte
<script lang="ts">
|
|
import { DropdownMenu } from "bits-ui";
|
|
import AlertBadge from "#lib/components/alerts/AlertBadge.svelte";
|
|
import AccountAvatar from "#lib/components/settings/AccountAvatar.svelte";
|
|
import AddAccountDialog from "#lib/components/settings/AddAccountDialog.svelte";
|
|
import Button from "#lib/components/ui/Button.svelte";
|
|
import Icon from "#lib/components/ui/Icon.svelte";
|
|
import { accountName } from "#lib/format/peer.js";
|
|
import { t } from "#lib/i18n/locale.svelte.js";
|
|
import type { MessageKey } from "#lib/i18n/messages.js";
|
|
import { accounts } from "#lib/stores/accounts.svelte.js";
|
|
import { theme } from "#lib/stores/theme.svelte.js";
|
|
import { type RightPanel, ui } from "#lib/stores/ui.svelte.js";
|
|
|
|
interface Entry {
|
|
icon: string;
|
|
label: MessageKey;
|
|
panel: RightPanel;
|
|
}
|
|
|
|
const DIGIT = /^Digit([1-9])$/;
|
|
|
|
const entries: Entry[] = [
|
|
{ icon: "eye", label: "settings.watches", panel: "watches" },
|
|
{ icon: "unmute", label: "settings.alerts", panel: "alerts" },
|
|
{ icon: "data", label: "settings.storage", panel: "storage" },
|
|
{ icon: "play-story", label: "settings.stories", panel: "stories-all" },
|
|
{ icon: "cloud-download", label: "settings.jobs", panel: "jobs" },
|
|
{ icon: "permissions", label: "settings.policy", panel: "policy" },
|
|
];
|
|
|
|
let adding = $state(false);
|
|
|
|
function onkeydown(event: KeyboardEvent) {
|
|
const match = DIGIT.exec(event.code);
|
|
if (!(event.altKey && match)) {
|
|
return;
|
|
}
|
|
const account = accounts.list[Number(match[1]) - 1];
|
|
if (account) {
|
|
event.preventDefault();
|
|
accounts.switchTo(account.account_id);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<svelte:window {onkeydown} />
|
|
|
|
<DropdownMenu.Root>
|
|
<DropdownMenu.Trigger>
|
|
{#snippet child({
|
|
props,
|
|
})}
|
|
<span class="menu-trigger">
|
|
<Button
|
|
{...props}
|
|
aria-label={t("menu.open")}
|
|
round
|
|
smaller
|
|
variant="translucent"
|
|
>
|
|
<Icon name="menu" />
|
|
</Button>
|
|
<AlertBadge />
|
|
</span>
|
|
{/snippet}
|
|
</DropdownMenu.Trigger>
|
|
<DropdownMenu.Portal>
|
|
<DropdownMenu.Content
|
|
align="start"
|
|
class="bg-menu-content main-menu"
|
|
sideOffset={6}
|
|
>
|
|
{#each accounts.list as account (account.account_id)}
|
|
<DropdownMenu.Item
|
|
class="bg-menu-item account-item"
|
|
onSelect={() => accounts.switchTo(account.account_id)}
|
|
>
|
|
<AccountAvatar {account} size={1.75} />
|
|
<span class="account-name">{accountName(account)}</span>
|
|
{#if !account.is_active}
|
|
<span class="account-tag">{t("menu.archived")}</span>
|
|
{/if}
|
|
{#if account.account_id === accounts.selectedId}
|
|
<Icon class="account-check" name="check" size="1.125rem" />
|
|
{/if}
|
|
</DropdownMenu.Item>
|
|
{/each}
|
|
<DropdownMenu.Item
|
|
class="bg-menu-item"
|
|
onSelect={() => {
|
|
adding = true;
|
|
}}
|
|
>
|
|
<Icon name="add" size="1.125rem" />
|
|
{t("menu.addAccount")}
|
|
</DropdownMenu.Item>
|
|
<DropdownMenu.Separator class="bg-menu-separator" />
|
|
<DropdownMenu.Item
|
|
class="bg-menu-item"
|
|
onSelect={() => ui.openSettings()}
|
|
>
|
|
<Icon name="settings" size="1.125rem" />
|
|
{t("settings.title")}
|
|
</DropdownMenu.Item>
|
|
{#each entries as entry (entry.panel)}
|
|
<DropdownMenu.Item
|
|
class="bg-menu-item"
|
|
onSelect={() => ui.openPanel(entry.panel)}
|
|
>
|
|
<Icon name={entry.icon} size="1.125rem" />
|
|
{#if entry.panel === "alerts"}
|
|
<span class="account-name">{t(entry.label)}</span>
|
|
<AlertBadge inline />
|
|
{:else}
|
|
{t(entry.label)}
|
|
{/if}
|
|
</DropdownMenu.Item>
|
|
{/each}
|
|
<DropdownMenu.Separator class="bg-menu-separator" />
|
|
<DropdownMenu.Item
|
|
class="bg-menu-item"
|
|
closeOnSelect={false}
|
|
onSelect={() => theme.toggle()}
|
|
>
|
|
<Icon name="darkmode" size="1.125rem" />
|
|
<span class="account-name">{t("menu.nightMode")}</span>
|
|
{#if theme.resolved === "dark"}
|
|
<Icon class="account-check" name="check" size="1.125rem" />
|
|
{/if}
|
|
</DropdownMenu.Item>
|
|
</DropdownMenu.Content>
|
|
</DropdownMenu.Portal>
|
|
</DropdownMenu.Root>
|
|
|
|
<AddAccountDialog bind:open={adding} />
|
|
|
|
<style lang="scss">
|
|
.menu-trigger {
|
|
position: relative;
|
|
display: flex;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
:global(.main-menu) {
|
|
width: 17rem;
|
|
max-height: calc(100dvh - 5rem);
|
|
overflow-y: auto;
|
|
}
|
|
|
|
:global(.main-menu .account-item) {
|
|
padding-block: 0.375rem;
|
|
}
|
|
|
|
.account-name {
|
|
overflow: hidden;
|
|
flex: 1;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.account-tag {
|
|
flex-shrink: 0;
|
|
font-size: 0.75rem;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
:global(.main-menu .account-check) {
|
|
flex-shrink: 0;
|
|
color: var(--color-primary);
|
|
}
|
|
</style>
|