Files
kycnotme/web/src/components/UserBadge.astro
2025-05-22 11:10:18 +00:00

88 lines
2.0 KiB
Plaintext

---
import { tv, type VariantProps } from 'tailwind-variants'
import { getSizePxFromTailwindClasses } from '../lib/tailwind'
import MyPicture from './MyPicture.astro'
import type { Prisma } from '@prisma/client'
import type { HTMLAttributes } from 'astro/types'
import type { O } from 'ts-toolbelt'
const userBadge = tv({
slots: {
base: 'group/user-badge font-title inline-flex max-w-full items-center gap-1 overflow-hidden font-medium',
image: 'inline-block rounded-full object-cover',
text: 'truncate',
},
variants: {
size: {
sm: {
base: 'gap-1 text-xs',
image: 'size-4',
},
md: {
base: 'gap-2 text-sm',
image: 'size-5',
},
lg: {
base: 'gap-2 text-base',
image: 'size-6',
},
},
noLink: {
true: {
text: 'cursor-default',
},
false: {
base: 'cursor-pointer',
text: 'group-hover/user-badge:underline',
},
},
},
defaultVariants: {
size: 'sm',
noLink: false,
},
})
type Props = O.Optional<HTMLAttributes<'a'>, 'href'> &
VariantProps<typeof userBadge> & {
user: Prisma.UserGetPayload<{
select: {
name: true
displayName: true
picture: true
}
}>
classNames?: {
image?: string
text?: string
}
children?: never
}
const { user, href, class: className, size = 'sm', classNames, noLink = false, ...htmlProps } = Astro.props
const { base, image, text } = userBadge({ size, noLink })
const imageClassName = image({ class: classNames?.image })
const imageSizePx = getSizePxFromTailwindClasses(imageClassName, 16)
const Tag = noLink ? 'span' : 'a'
---
<Tag
href={Tag === 'a' ? (href ?? `/u/${user.name}`) : undefined}
class={base({ class: className })}
{...htmlProps}
>
{
!!user.picture && (
<MyPicture src={user.picture} height={imageSizePx} width={imageSizePx} class={imageClassName} alt="" />
)
}
<span class={text({ class: classNames?.text })}>
{user.displayName ?? user.name}
</span>
</Tag>