Something went wrong. Try again.
FlockOff is a mass-block tool for the Atmosphere flockoff.app
Something went wrong. Try again.
4.0 kB · 116 lines
TSX
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'import { Checkbox } from '@/components/ui/checkbox'import { buildProfileUrl } from '@/lib/utils'import type { EngagementAccount } from '@/types'
interface AccountCardProps { account: EngagementAccount selected: boolean onToggle: () => void}
const RELATIONSHIP_STYLE = { mutual: { label: 'Mutual', badgeClass: 'border-[var(--fo-mutual-border)] bg-[var(--fo-mutual-bg)] text-[var(--fo-mutual)]', ringClass: 'ring-1 ring-[var(--fo-mutual)]/15', }, following: { label: 'Following', badgeClass: 'border-[var(--fo-following-border)] bg-[var(--fo-following-bg)] text-[var(--fo-following)]', ringClass: 'ring-1 ring-[var(--fo-following)]/15', }, follower: { label: 'Follows you', badgeClass: 'border-[var(--fo-follower-border)] bg-[var(--fo-follower-bg)] text-[var(--fo-follower)]', ringClass: '', }, none: null,} as const
const TYPE_LABEL: Record<string, string> = { op: 'OP', like: 'Liked', repost: 'Reposted', quote: 'Quoted', reply: 'Replied',}
export function AccountCard({ account, selected, onToggle }: AccountCardProps) { const { profile, relationship, engagementTypes, comments, commentCount } = account const relStyle = RELATIONSHIP_STYLE[relationship] const hasComments = !!comments?.length // comments arrive capped server-side; commentCount carries the true total const hiddenComments = hasComments ? (commentCount ?? comments!.length) - comments!.length : 0
return ( <div className={`flex ${hasComments ? 'items-start' : 'items-center'} gap-3 px-3 py-3 rounded-lg cursor-pointer transition-colors ${ selected ? `border-l-2 border-[var(--fo-ember)] hover:bg-secondary/60 ${relStyle?.ringClass ?? ''}` : 'border-l-2 border-transparent opacity-50 hover:bg-secondary/60' }`} onClick={onToggle} > <Checkbox checked={selected} onCheckedChange={onToggle} onClick={(e) => e.stopPropagation()} className="shrink-0" />
<Avatar className="h-8 w-8 shrink-0"> <AvatarImage src={profile.avatar} alt={profile.displayName ?? profile.handle} /> <AvatarFallback className="text-xs bg-[var(--fo-ember)] text-white"> {(profile.displayName ?? profile.handle).charAt(0).toUpperCase()} </AvatarFallback> </Avatar>
<div className="min-w-0 flex-1"> <div className="flex items-center gap-1.5 flex-wrap"> <a href={buildProfileUrl(profile.handle)} target="_blank" rel="noopener noreferrer" className="font-medium text-sm hover:underline truncate" onClick={(e) => e.stopPropagation()} > {profile.displayName ?? profile.handle} </a> {relStyle && ( <span className={`text-[0.65rem] font-mono px-1.5 py-0.5 rounded-full border ${relStyle.badgeClass}`}> {relStyle.label} </span> )} </div> <p className="text-xs font-mono text-[var(--fo-text3)] truncate">@{profile.handle}</p>
{hasComments && ( <div className="mt-1.5 flex flex-col gap-1"> {comments!.map((comment) => ( <p key={comment.uri} className="text-xs text-[var(--fo-text2)] border-l-2 border-border pl-2 line-clamp-2" > {comment.text} </p> ))} {hiddenComments > 0 && ( <p className="text-[0.65rem] font-mono text-[var(--fo-text3)]"> +{hiddenComments} more </p> )} </div> )} </div>
<div className="flex gap-1.5 flex-wrap justify-end shrink-0"> {engagementTypes.map((type) => ( <span key={type} className="text-xs font-mono text-[var(--fo-text3)]"> {TYPE_LABEL[type] ?? type} </span> ))} </div> </div> )}