Files
2026-10-03 23:45:04 +02:00

136 lines
5.2 KiB
Vue

<script setup lang="ts">
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
const { user, can, logout } = useAuth()
const { uniform, toggle: toggleGridMode } = useGridMode()
const { open: paletteOpen } = useCommandPalette()
const route = useRoute()
async function onLogoClick(e: MouseEvent) {
if (route.path !== '/') return
e.preventDefault()
await refreshNuxtData()
}
const initials = computed(() => user.value?.name.slice(0, 2).toUpperCase() ?? '')
async function onLogout() {
await logout()
await navigateTo('/')
}
</script>
<template>
<header class="sticky top-0 z-10 flex h-(--header-height) shrink-0 items-center gap-2 border-b bg-background">
<div class="flex w-full items-center gap-1 px-4 lg:gap-2 lg:px-6">
<NuxtLink
to="/"
class="mr-2 font-logo text-[2.4rem] leading-none tracking-tight transition-colors hover:text-accent"
@click="onLogoClick"
>
BRETT
</NuxtLink>
<UploadPopover />
<Button variant="ghost" as-child>
<NuxtLink to="/users" class="flex items-center gap-1.5">
<Icon name="ph:users-fill" class="size-4" />
{{ $t('nav.users') }}
</NuxtLink>
</Button>
<Button v-if="can('admin.access')" variant="ghost" as-child>
<NuxtLink to="/admin" class="flex items-center gap-1.5">
<Icon name="ph:shield-fill" class="size-4" />
Admin
</NuxtLink>
</Button>
<button
type="button"
class="ml-auto flex h-9 cursor-pointer items-center gap-2 rounded-md border bg-muted/40 px-3 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
:aria-label="$t('nav.searchAria')"
@click="paletteOpen = true"
>
<Icon name="ph:magnifying-glass-fill" class="size-4" />
<span class="hidden text-left sm:inline">{{ $t('nav.search') }}</span>
<kbd class="hidden rounded-sm border bg-background px-1.5 text-xs sm:inline">{{ $t('nav.searchShortcut') }}</kbd>
</button>
<div class="flex items-center gap-3">
<Tooltip>
<TooltipTrigger as-child>
<Button
variant="ghost"
size="icon"
@click="toggleGridMode"
>
<Icon name="ph:grid-nine-fill" v-if="uniform" class="size-5" />
<Icon name="ph:squares-four-fill" v-else class="size-5" />
</Button>
</TooltipTrigger>
<TooltipContent>{{ uniform ? $t('nav.gridBento') : $t('nav.gridUniform') }}</TooltipContent>
</Tooltip>
<ThemeSelector />
<template v-if="user">
<NotificationBell />
<DropdownMenu>
<DropdownMenuTrigger class="flex cursor-pointer items-center gap-2 rounded-md px-1 py-0.5 outline-none hover:bg-accent">
<Avatar class="size-8">
<AvatarImage v-if="user.avatarUrl" :src="user.avatarUrl" :alt="user.name" />
<AvatarFallback
class="text-xs"
:style="user.color ? { backgroundColor: user.color, color: '#fff' } : undefined"
>
{{ initials }}
</AvatarFallback>
</Avatar>
<span
class="text-sm font-medium"
:style="user.color ? { color: user.color } : undefined"
>{{ user.name }}</span>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" class="w-44">
<DropdownMenuLabel class="truncate">
{{ user.name }}
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem as-child>
<NuxtLink :to="`/user/${user.id}`" class="flex items-center gap-2">
<Icon name="ph:user-fill" class="size-4" />
{{ $t('nav.profile') }}
</NuxtLink>
</DropdownMenuItem>
<DropdownMenuItem as-child>
<NuxtLink to="/settings" class="flex items-center gap-2">
<Icon name="ph:gear-fill" class="size-4" />
{{ $t('nav.settings') }}
</NuxtLink>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive" class="flex items-center gap-2" @click="onLogout">
<Icon name="ph:sign-out-fill" class="size-4" />
{{ $t('auth.logout') }}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</template>
<template v-else>
<Button variant="ghost" as-child>
<NuxtLink to="/login">{{ $t('auth.login') }}</NuxtLink>
</Button>
<Button as-child>
<NuxtLink to="/register">{{ $t('auth.register') }}</NuxtLink>
</Button>
</template>
</div>
</div>
</header>
</template>