crush-level-web/src/app/(main)/profile/components/CharacterCard.tsx

107 lines
3.5 KiB
TypeScript
Raw Normal View History

2025-11-28 06:31:36 +00:00
import { Tag } from '@/components/ui/tag'
import { cn, formatNumberToKMB } from '@/lib/utils'
import { AIPermission, AiUserBaseListOutput } from '@/services/create'
import Image from 'next/image'
import Link from 'next/link'
2025-11-13 08:38:25 +00:00
2025-11-28 06:31:36 +00:00
const CharacterCard = ({
character,
isHovered,
onHover,
}: {
character: AiUserBaseListOutput
isHovered: boolean
onHover: (hovered: boolean) => void
2025-11-13 08:38:25 +00:00
}) => {
// 根据权限判断是否私密
2025-11-28 06:31:36 +00:00
const isPrivate = character.permission === AIPermission.Private
2025-11-13 08:38:25 +00:00
return (
<Link href={`/@${character.aiId}`}>
2025-11-28 06:31:36 +00:00
<div
className="group flex w-full min-w-[200px] grow basis-0 flex-col gap-3"
2025-11-13 08:38:25 +00:00
onMouseEnter={() => onHover(true)}
onMouseLeave={() => onHover(false)}
>
{/* 角色图片 */}
2025-11-28 06:31:36 +00:00
<div
className="relative overflow-hidden rounded-lg bg-cover bg-center bg-no-repeat pb-[133%]"
style={
{
// backgroundImage: character.homeImageUrl ? `url('${character.homeImageUrl}')` : 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'
}
}
2025-11-13 08:38:25 +00:00
>
2025-11-28 06:31:36 +00:00
<Image
2025-11-13 08:38:25 +00:00
src={character.homeImageUrl ?? ''}
alt={character.nickname ?? ''}
fill
className="object-cover object-top"
sizes="100%"
/>
{/* 私密标识 */}
2025-11-28 06:31:36 +00:00
<div className="bg-surface-element-dark-normal absolute top-2 right-2 z-[1] flex h-6 w-6 items-center justify-center rounded-xs backdrop-blur-xs">
<i
className={cn('iconfont !text-[12px]', {
'icon-eye-off': isPrivate,
'icon-eye-on': !isPrivate,
})}
/>
2025-11-13 08:38:25 +00:00
</div>
{/* 底部遮罩层 */}
2025-11-28 06:31:36 +00:00
<div
className={cn(
'absolute right-0 bottom-0 left-0 flex flex-col justify-end bg-gradient-to-b from-transparent to-black px-3 pb-3',
{
'pt-6': !isHovered,
'h-full pt-12': isHovered,
}
)}
>
2025-11-13 08:38:25 +00:00
{/* 描述文字 - hover时显示带过渡动效 */}
2025-11-28 06:31:36 +00:00
<div
className={cn(
'txt-body-m mb-2 line-clamp-6 transform overflow-hidden text-white transition-all duration-300 ease-in-out',
{
'max-h-0 opacity-0': !isHovered,
'h-full max-h-max opacity-100': isHovered,
}
)}
2025-11-13 08:38:25 +00:00
>
{character.introduction || ''}
</div>
2025-11-28 06:31:36 +00:00
2025-11-13 08:38:25 +00:00
{/* 点赞数 - 暂时用固定值实际应该从API获取 */}
2025-11-28 06:31:36 +00:00
<div className="flex h-6 items-center gap-1 px-1 py-0.5">
2025-11-13 08:38:25 +00:00
{/* <img src={likeIcon} alt="点赞" className="w-3 h-3" /> */}
<i className="iconfont icon-Like-fill" />
2025-11-28 06:31:36 +00:00
<span className="text-xs font-medium text-white">
{formatNumberToKMB(character.likedNum ?? 0)}
</span>
2025-11-13 08:38:25 +00:00
</div>
</div>
</div>
{/* 角色信息 */}
<div className="flex flex-col gap-2">
{/* 角色名称 */}
2025-11-28 06:31:36 +00:00
<div className="txt-title-m truncate">{character.nickname}</div>
2025-11-13 08:38:25 +00:00
{/* 标签 */}
<div className="flex flex-wrap gap-1">
{/* 性格标签 */}
2025-11-28 06:31:36 +00:00
{character.characterName && <Tag size="small">{character.characterName}</Tag>}
2025-11-13 08:38:25 +00:00
{/* 标签 */}
2025-11-28 06:31:36 +00:00
{character.tagName && <Tag size="small">{character.tagName}</Tag>}
2025-11-13 08:38:25 +00:00
</div>
</div>
</div>
</Link>
2025-11-28 06:31:36 +00:00
)
}
export default CharacterCard