forked from BRETT/BRETT
Initial Commit
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
} from '@/components/ui/sidebar'
|
||||
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
|
||||
import type { CommentAttachment } from '~~/shared/utils/attachments'
|
||||
|
||||
interface LatestComment {
|
||||
id: number
|
||||
content: string
|
||||
createdAt: string
|
||||
userName: string
|
||||
userId: number
|
||||
userColor: string | null
|
||||
userAvatarUrl: string | null
|
||||
uploadId: string
|
||||
attachments?: CommentAttachment[]
|
||||
}
|
||||
|
||||
const { data: comments } = await useFetch<LatestComment[]>('/api/comments/latest', {
|
||||
key: 'latest-comments',
|
||||
default: () => [],
|
||||
})
|
||||
const { liveComments } = useLiveComments()
|
||||
const timeAgo = useTimeAgo()
|
||||
|
||||
const mergedComments = computed(() => {
|
||||
const seen = new Set<number>()
|
||||
return [...liveComments.value, ...comments.value]
|
||||
.filter((c) => {
|
||||
if (seen.has(c.id)) return false
|
||||
seen.add(c.id)
|
||||
return true
|
||||
})
|
||||
.slice(0, 15)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Sidebar side="right" collapsible="none" class="sticky top-0 hidden h-svh shrink-0 overflow-hidden rounded-l-md border-l lg:flex">
|
||||
<SidebarContent class="px-2 py-2">
|
||||
<p v-if="!mergedComments.length" class="px-2 py-1 text-sm text-muted-foreground">
|
||||
Noch keine Kommentare.
|
||||
</p>
|
||||
<NuxtLink
|
||||
v-for="comment in mergedComments"
|
||||
:key="comment.id"
|
||||
:to="`/thread/${comment.uploadId}#comment-${comment.id}`"
|
||||
class="block rounded-md border border-sidebar-border/60 bg-sidebar px-3 py-2.5 text-sm transition-colors hover:border-sidebar-border hover:bg-sidebar-accent"
|
||||
>
|
||||
<div class="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<NuxtImg
|
||||
v-if="comment.userAvatarUrl"
|
||||
:src="comment.userAvatarUrl"
|
||||
:alt="comment.userName"
|
||||
width="28"
|
||||
height="28"
|
||||
fit="cover"
|
||||
class="size-7 shrink-0 rounded-sm"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="flex size-7 shrink-0 items-center justify-center rounded-sm text-xs font-medium"
|
||||
:style="comment.userColor ? { backgroundColor: comment.userColor, color: '#fff' } : { backgroundColor: 'var(--color-muted)' }"
|
||||
>{{ comment.userName.slice(0, 2).toUpperCase() }}</span>
|
||||
<UserHoverCard
|
||||
:user-id="comment.userId"
|
||||
:user-name="comment.userName"
|
||||
:user-color="comment.userColor"
|
||||
:user-avatar-url="comment.userAvatarUrl"
|
||||
>
|
||||
<span
|
||||
class="truncate text-sm font-medium text-foreground hover:underline"
|
||||
:style="comment.userColor ? { color: comment.userColor } : undefined"
|
||||
@click.stop.prevent="navigateTo(`/user/${comment.userId}`)"
|
||||
>{{ comment.userName }}</span>
|
||||
</UserHoverCard>
|
||||
<span class="shrink-0">· {{ timeAgo(comment.createdAt) }}</span>
|
||||
</div>
|
||||
<HoverCard :open-delay="250" :close-delay="100">
|
||||
<HoverCardTrigger as-child>
|
||||
<div class="mt-1.5 line-clamp-3 break-words">
|
||||
<CommentContent :content="comment.content" compact /><CommentAttachments v-if="comment.attachments?.length" :attachments="comment.attachments" compact />
|
||||
</div>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent side="left" align="start" class="w-80 max-w-[90vw] text-sm">
|
||||
<div class="max-h-64 overflow-y-auto break-words">
|
||||
<CommentContent :content="comment.content" />
|
||||
<CommentAttachments v-if="comment.attachments?.length" :attachments="comment.attachments" />
|
||||
</div>
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
</NuxtLink>
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
</template>
|
||||
Reference in New Issue
Block a user