forked from BRETT/BRETT
84 lines
3.0 KiB
Vue
84 lines
3.0 KiB
Vue
<script setup lang="ts">
|
|
import { Button } from '@/components/ui/button'
|
|
import {
|
|
Popover,
|
|
PopoverContent,
|
|
PopoverTrigger,
|
|
} from '@/components/ui/popover'
|
|
import type { AppNotification } from '@/composables/useNotifications'
|
|
|
|
const { notifications, unreadCount, markRead } = useNotifications()
|
|
const open = ref(false)
|
|
const timeAgo = useTimeAgo()
|
|
|
|
async function goTo(n: AppNotification) {
|
|
open.value = false
|
|
await markRead(n.id)
|
|
await navigateTo(`/thread/${n.uploadId}#comment-${n.commentId}`)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Popover v-model:open="open">
|
|
<PopoverTrigger as-child>
|
|
<Button variant="ghost" size="icon" class="relative" aria-label="Benachrichtigungen">
|
|
<Icon name="ph:bell-fill" class="size-5" />
|
|
<span
|
|
v-if="unreadCount"
|
|
class="absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-accent px-1 text-[10px] font-semibold text-accent-foreground"
|
|
>{{ unreadCount > 9 ? '9+' : unreadCount }}</span>
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent align="end" class="w-80 gap-0 p-0">
|
|
<div class="max-h-96 overflow-y-auto">
|
|
<p v-if="!notifications.length" class="px-4 py-6 text-center text-sm text-muted-foreground">
|
|
Keine Benachrichtigungen.
|
|
</p>
|
|
<button
|
|
v-for="n in notifications"
|
|
:key="n.id"
|
|
type="button"
|
|
class="flex w-full items-center gap-3 border-b px-4 py-3 text-left text-sm transition-colors last:border-b-0 hover:bg-accent/10"
|
|
@click="goTo(n)"
|
|
>
|
|
<div class="size-12 shrink-0 overflow-hidden rounded-md bg-muted">
|
|
<NuxtImg
|
|
v-if="n.thumbUrl"
|
|
:src="n.thumbUrl"
|
|
:alt="n.actorName"
|
|
width="96"
|
|
height="96"
|
|
fit="cover"
|
|
class="h-full w-full object-cover"
|
|
/>
|
|
<video
|
|
v-else-if="n.uploadType === 'video'"
|
|
:src="n.url"
|
|
preload="metadata"
|
|
muted
|
|
playsinline
|
|
class="h-full w-full object-cover"
|
|
/>
|
|
<div v-else class="flex h-full w-full items-center justify-center">
|
|
<Icon name="ph:link-fill" class="size-4 text-muted-foreground" />
|
|
</div>
|
|
</div>
|
|
<div class="min-w-0 flex-1">
|
|
<div class="flex items-baseline gap-1.5">
|
|
<span
|
|
class="truncate font-medium"
|
|
:style="n.actorColor ? { color: n.actorColor } : undefined"
|
|
>{{ n.actorName }}</span>
|
|
<span class="shrink-0 text-muted-foreground">{{ n.isMention ? 'hat dich erwähnt' : 'hat kommentiert' }}</span>
|
|
<span class="ml-auto shrink-0 text-xs text-muted-foreground">{{ timeAgo(n.createdAt) }}</span>
|
|
</div>
|
|
<p class="mt-0.5 line-clamp-2 break-words text-muted-foreground">
|
|
{{ n.content }}
|
|
</p>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
</template>
|