SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%
3.1 KB · 95 lines tsx
Raw Blame History
1import { Evidence } from '@/components/evidence/evidence';2import { cn } from '@/lib/cn';3import { fmtAgo } from '@/lib/format';4import type { ProvenanceEntry } from '@/lib/types';5import { TierBadge } from './badges';67function domain(url: string | null | undefined): string | null {8  if (!url) return null;9  try {10    return new URL(url).hostname.replace(/^www\./, '');11  } catch {12    return null;13  }14}1516/**17 * One-line provenance: "Source: docs.claude.com · T1 · observed 3 h ago · high". Server-safe.18 * With `slug` + `property` it appends an "Evidence" trigger that opens the drawer (`components/evidence`).19 */20export function ProvenanceInline({21  p,22  className,23  showConfidence = true,24  slug,25  property,26  value,27  entity,28}: {29  p: ProvenanceEntry;30  className?: string;31  showConfidence?: boolean;32  slug?: string;33  property?: string;34  value?: unknown;35  entity?: { name?: string; entity_type?: string } | null;36}) {37  const name = p.source_name ?? domain(p.url) ?? 'source';38  return (39    <p className={cn('flex flex-wrap items-center gap-x-1.5 gap-y-0.5 text-[11px] leading-4 text-ink-3', className)}>40      <span>Source:</span>41      {p.url ? (42        <a href={p.url} target="_blank" rel="noopener noreferrer" className="truncate text-ink-2 hover:text-accent hover:underline">43          {name}44        </a>45      ) : (46        <span className="text-ink-2">{name}</span>47      )}48      <span aria-hidden>·</span>49      <TierBadge tier={p.tier} />50      <span aria-hidden>·</span>51      <span title={p.observed_at}>observed {fmtAgo(p.observed_at)}</span>52      {showConfidence && p.confidence && (53        <>54          <span aria-hidden>·</span>55          <span className={cn(p.confidence === 'conflicted' && 'text-danger', p.confidence === 'low' && 'text-warning')}>{p.confidence}</span>56        </>57      )}58      {p.extractor && p.extractor.startsWith('llm') && (59        <>60          <span aria-hidden>·</span>61          <span title="Extracted by the local LLM factory">LLM-extracted</span>62        </>63      )}64      {slug && property && (65        <>66          <span aria-hidden>·</span>67          <Evidence slug={slug} property={property} value={value} unit={p.unit ?? null} fallback={p} entity={entity ?? null} className="text-accent">68            Evidence69          </Evidence>70        </>71      )}72    </p>73  );74}7576/** Compact source cell for tables: domain link + tier. */77export function SourceCell({ url, tier, name, observedAt, className }: { url: string | null | undefined; tier?: number | null; name?: string | null; observedAt?: string | null; className?: string }) {78  const label = name ?? domain(url);79  return (80    <span className={cn('inline-flex flex-wrap items-center gap-1.5 text-xs text-ink-3', className)}>81      {url && label ? (82        <a href={url} target="_blank" rel="noopener noreferrer" className="max-w-[16rem] truncate text-ink-2 hover:text-accent hover:underline">83          {label}84        </a>85      ) : label ? (86        <span>{label}</span>87      ) : (88        <span>—</span>89      )}90      {tier !== undefined && <TierBadge tier={tier} />}91      {observedAt && <span title={observedAt}>{fmtAgo(observedAt)}</span>}92    </span>93  );94}95