import Link from 'next/link';
import { ExternalLink } from 'lucide-react';
import { cn, fmtMoney, fmtPct } from '@/lib/format';
import { feeBasisLabel } from '@rareindex/valuation';
import { catName, gradeLabel } from '@/lib/taxonomy';
import { Badge } from '@/components/ui/primitives';
/** Small shared building blocks for market tables and cards. */
import { Thumb } from '@/components/ui/tile-image';
export { Thumb };
export function CategoryTag({ slug, className }: { slug: string | null | undefined; className?: string }) {
if (!slug) return null;
return (
{catName(slug)}
);
}
export function GradeBadge({ grader, grade, className }: { grader: string | null | undefined; grade: string | null | undefined; className?: string }) {
const label = gradeLabel(grader, grade);
if (!label) return —;
return (
{label}
);
}
/** §178: source attribution with outbound link. */
export function SourceLink({ name, url, className }: { name: string; url: string | null | undefined; className?: string }) {
if (!url) return {name};
return (
{name}
);
}
export function PriceCell({ usd, native, currency, className }: { usd: number | null | undefined; native?: number | null; currency?: string | null; className?: string }) {
const showNative = native !== null && native !== undefined && currency && currency !== 'USD';
return (
{fmtMoney(usd)}
{showNative ? {fmtMoney(native, currency!)} : null}
);
}
export function AssetTitleCell({ slug, title, categorySlug, image, sub, size = 36 }: { slug: string; title: string; categorySlug?: string | null; image?: string | null; sub?: string | null; size?: number }) {
return (
{title}
{categorySlug ? catName(categorySlug) : null}
{sub ? (categorySlug ? ` · ${sub}` : sub) : null}
);
}
/** Heuristic sale verification label (§39, §205): verified · likely · unverified · excluded. Never a claim of independent confirmation. */
export function VerificationBadge({ label, reason, className }: { label: 'verified' | 'likely' | 'unverified' | 'excluded'; reason?: string; className?: string }) {
const tone = label === 'verified' ? 'gain' : label === 'likely' ? 'neutral' : 'alert';
const text = label === 'verified' ? 'Verified' : label === 'likely' ? 'Likely' : label === 'unverified' ? 'Unverified' : 'Excluded';
return (
{text}
);
}
/** Fee basis of an all-in figure (§35): premium included / added (published, ≈ estimated, default) / none / unknown. */
export function FeeBasisPill({ basis, rate, className }: { basis: string | null | undefined; rate?: number | null; className?: string }) {
if (!basis) return null;
const approx = basis === 'added_approximate' || basis === 'added_default';
const text =
basis === 'included' ? 'premium included' : basis === 'none' ? 'no buyer premium' : basis === 'unknown' ? 'fees unknown' : `+ premium ${approx ? '≈ ' : ''}${rate !== null && rate !== undefined ? fmtPct(rate, rate < 0.1 ? 1 : 0, false) : ''}`.trim();
const tone = basis === 'unknown' ? 'alert' : basis === 'included' || basis === 'none' ? 'neutral' : 'index';
return (
{text}
);
}
/** Buyer-pays amount in USD with the fee basis under it; falls back to the recorded price when no all-in figure exists. */
export function AllInCell({ allInUsd, priceUsd, basis, rate, className }: { allInUsd: number | null | undefined; priceUsd: number | null | undefined; basis?: string | null; rate?: number | null; className?: string }) {
const v = allInUsd ?? priceUsd;
const differs = allInUsd !== null && allInUsd !== undefined && priceUsd !== null && priceUsd !== undefined && Math.abs(allInUsd - priceUsd) >= 0.5;
return (
{basis === 'added_approximate' || basis === 'added_default' ? '≈ ' : ''}{fmtMoney(v)}
{differs || (basis && basis !== 'none') ? : null}
);
}