52 lines
1.9 KiB
TypeScript
52 lines
1.9 KiB
TypeScript
"use client"
|
|
|
|
import type { FamilyMember } from "@/types/family"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
interface FamilyNodeProps {
|
|
member: FamilyMember
|
|
spouse?: FamilyMember
|
|
isRoot?: boolean
|
|
onSelect?: (member: FamilyMember) => void
|
|
}
|
|
|
|
export function FamilyNode({ member, spouse, isRoot, onSelect }: FamilyNodeProps) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"relative flex flex-col items-center gap-2 p-3 rounded-lg border-2 transition-all cursor-pointer hover:scale-105 shadow-sm w-32",
|
|
isRoot ? "border-primary bg-primary/5" : "border-border bg-card",
|
|
member.gender === "female" ? "rounded-full w-28 h-28 justify-center" : "rounded-lg", // Traditional round sky/square earth or just variety
|
|
)}
|
|
onClick={() => onSelect?.(member)}
|
|
>
|
|
<div className="absolute -top-3 bg-background border border-border px-2 py-0.5 rounded-full text-[10px] text-muted-foreground font-mono">
|
|
{member.generation}世
|
|
</div>
|
|
|
|
<div className="h-10 w-10 rounded-full bg-muted flex items-center justify-center text-muted-foreground overflow-hidden border border-border/50">
|
|
{member.avatarUrl ? (
|
|
<img
|
|
src={member.avatarUrl || "/placeholder.svg"}
|
|
alt={member.fullName}
|
|
className="h-full w-full object-cover"
|
|
/>
|
|
) : (
|
|
<span className="font-serif font-bold text-lg text-foreground/70">{member.surname}</span>
|
|
)}
|
|
</div>
|
|
|
|
<div className="text-center">
|
|
<div className="font-serif font-bold text-foreground leading-tight">{member.givenName}</div>
|
|
{member.courtesyName && (
|
|
<div className="text-[10px] text-muted-foreground mt-0.5">字 {member.courtesyName}</div>
|
|
)}
|
|
</div>
|
|
|
|
{member.lifeStatus === "deceased" && (
|
|
<div className="absolute -top-1 -right-1 h-2 w-2 rounded-full bg-neutral-400 ring-2 ring-background" />
|
|
)}
|
|
</div>
|
|
)
|
|
}
|