← back to Stayclaim

src/components/SourceLink.tsx

69 lines

import Link from 'next/link';
import { safeHttpUrl } from '@/lib/url-guards';

/**
 * SourceLink — every fact in the archive must show its source.
 *
 * Renders a small "source: NAME ↗" link to the actual source document
 * (Socrata permit row, IA scanned page, Assessor portal, etc.). Steve's
 * editorial rule (2026-04-29): "real links back to the original source
 * showing the actual ocr piece of paper etc."
 */
export function SourceLink({
  label,
  url,
  tier,
  date,
  className = '',
}: {
  label: string;
  url?: string | null;
  tier?: string | null;          // 'A' | 'B' | 'C' | 'D'
  date?: string | null;
  className?: string;
}) {
  const tierLabel = tier ? { A: 'gov', B: 'verified', C: 'community', D: 'inferred' }[tier] ?? tier : null;
  const tierColor = tier ? {
    A: 'text-moss',
    B: 'text-blue-700',
    C: 'text-amber-700',
    D: 'text-ink/40',
  }[tier] ?? 'text-ink/40' : '';
  const safeUrl = safeHttpUrl(url);

  return (
    <span className={`font-mono text-[10px] uppercase tracking-[0.15em] text-ink/45 ${className}`}>
      source:{' '}
      {safeUrl ? (
        <a
          href={safeUrl}
          target="_blank"
          rel="noreferrer noopener"
          className="hover:text-coral underline-offset-2 hover:underline transition"
        >
          {label} ↗
        </a>
      ) : (
        <span className="text-ink/65">{label}</span>
      )}
      {tierLabel && (
        <span className={`ml-2 ${tierColor}`}>tier {tier} · {tierLabel}</span>
      )}
      {date && <span className="ml-2">· {date.slice(0, 10)}</span>}
    </span>
  );
}

/** Compact sourcing block for tabular contexts (permit/event rows). */
export function SourceLinkInline({ label, url }: { label: string; url?: string | null }) {
  const safeUrl = safeHttpUrl(url);
  return safeUrl ? (
    <a href={safeUrl} target="_blank" rel="noreferrer noopener"
       className="font-mono text-[10px] uppercase tracking-[0.1em] text-coral hover:underline">
      {label} ↗
    </a>
  ) : (
    <span className="font-mono text-[10px] uppercase tracking-[0.1em] text-ink/40">{label}</span>
  );
}