forked from BRETT/BRETT
116 lines
4.6 KiB
Vue
116 lines
4.6 KiB
Vue
<script setup lang="ts">
|
|
import type { CardBorderEffectKey } from '~~/shared/utils/cardBorderEffects'
|
|
import type { CardEffectKey } from '~~/shared/utils/cardEffects'
|
|
import CardBackgroundEffect from '@/components/effects/CardBackgroundEffect.vue'
|
|
import CardBorderEffect from '@/components/effects/CardBorderEffect.vue'
|
|
import CardVignette from '@/components/effects/CardVignette.vue'
|
|
import { isCardBorderEffect } from '~~/shared/utils/cardBorderEffects'
|
|
import { isCardEffect } from '~~/shared/utils/cardEffects'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
interface ListedUser {
|
|
id: number
|
|
name: string
|
|
color: string | null
|
|
avatarUrl: string | null
|
|
cardEffect: string | null
|
|
cardEffectColor: string | null
|
|
cardVignette: boolean
|
|
cardBorderEffect: string | null
|
|
cardBorderEffectColor: string | null
|
|
createdAt: string
|
|
stats: {
|
|
uploads: number
|
|
comments: number
|
|
}
|
|
}
|
|
|
|
const { locale } = useI18n()
|
|
|
|
const { data: users } = await useFetch<ListedUser[]>('/api/users', {
|
|
key: 'users-list',
|
|
default: () => [],
|
|
})
|
|
|
|
function cardEffect(user: ListedUser): CardEffectKey | null {
|
|
return user.cardEffect && isCardEffect(user.cardEffect) ? user.cardEffect : null
|
|
}
|
|
|
|
function cardBorderEffect(user: ListedUser): CardBorderEffectKey | null {
|
|
return user.cardBorderEffect && isCardBorderEffect(user.cardBorderEffect) ? user.cardBorderEffect : null
|
|
}
|
|
|
|
const GRID_COLS = 'grid-cols-[2.5rem_minmax(0,1fr)_3rem_2.5rem_2.5rem] sm:grid-cols-[2.5rem_minmax(0,1fr)_3.5rem_4.5rem_4.5rem_10rem]'
|
|
|
|
function joinDate(value: string) {
|
|
return new Intl.DateTimeFormat(locale.value, { dateStyle: 'medium' }).format(new Date(value))
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="px-4 lg:px-6">
|
|
<h1 class="mb-4 text-xl font-semibold">
|
|
{{ $t('nav.users') }}
|
|
</h1>
|
|
|
|
<p v-if="!users.length" class="text-sm text-muted-foreground">
|
|
{{ $t('misc.noUsers') }}
|
|
</p>
|
|
|
|
<div v-else class="max-w-4xl overflow-x-auto">
|
|
<div :class="cn('grid items-center gap-3 px-3 py-2 text-xs text-muted-foreground', GRID_COLS)">
|
|
<span />
|
|
<span>{{ $t('common.name') }}</span>
|
|
<span class="text-right">ID</span>
|
|
<span class="hidden text-right sm:block">{{ $t('misc.uploadsCol') }}</span>
|
|
<span class="hidden text-right sm:block">{{ $t('misc.commentsCol') }}</span>
|
|
<span class="hidden text-right sm:block">{{ $t('misc.joined') }}</span>
|
|
</div>
|
|
|
|
<div class="mt-1 flex flex-col gap-2">
|
|
<NuxtLink
|
|
v-for="user in users"
|
|
:key="user.id"
|
|
:to="`/user/${user.id}`"
|
|
:class="cn(
|
|
'relative block overflow-hidden rounded-md border transition-colors',
|
|
cardBorderEffect(user) ? 'border-transparent' : 'hover:border-primary/50',
|
|
)"
|
|
>
|
|
<div v-if="cardEffect(user)" class="pointer-events-none absolute inset-0 overflow-hidden rounded-[inherit] [clip-path:inset(0_round_var(--radius-md))]">
|
|
<CardBackgroundEffect :effect="cardEffect(user)!" :color="user.cardEffectColor ?? user.color ?? '#6366f1'" />
|
|
<div class="absolute inset-0 bg-background/60" />
|
|
<CardVignette v-if="user.cardVignette" surface="var(--color-background)" />
|
|
</div>
|
|
<CardBorderEffect v-if="cardBorderEffect(user)" :effect="cardBorderEffect(user)!" :color="user.cardBorderEffectColor ?? user.color ?? '#6366f1'" />
|
|
|
|
<div :class="cn('relative grid items-center gap-3 px-3 py-2.5', GRID_COLS)">
|
|
<NuxtImg
|
|
v-if="user.avatarUrl"
|
|
:src="user.avatarUrl"
|
|
:alt="user.name"
|
|
width="40"
|
|
height="40"
|
|
fit="cover"
|
|
class="size-10 shrink-0 rounded-sm"
|
|
/>
|
|
<span
|
|
v-else
|
|
class="flex size-10 shrink-0 items-center justify-center rounded-sm text-xs font-medium"
|
|
:style="user.color ? { backgroundColor: user.color, color: '#fff' } : { backgroundColor: 'var(--color-muted)' }"
|
|
>{{ user.name.slice(0, 2).toUpperCase() }}</span>
|
|
<span
|
|
class="truncate font-medium"
|
|
:style="user.color ? { color: user.color } : undefined"
|
|
>{{ user.name }}</span>
|
|
<span class="text-right text-sm text-muted-foreground">{{ user.id }}</span>
|
|
<span class="hidden text-right text-sm sm:block">{{ user.stats.uploads }}</span>
|
|
<span class="hidden text-right text-sm sm:block">{{ user.stats.comments }}</span>
|
|
<span class="hidden text-right text-sm text-muted-foreground sm:block">{{ joinDate(user.createdAt) }}</span>
|
|
</div>
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|