Web: single provenance popover per evidence table, compact row badges
2 changed files +18 −3
modified
apps/web/src/components/data/evidence-table.tsx
+8 −2
@@ -26,8 +26,15 @@ function DirectionBadge({ e }: { e: EvidenceItem }) { | |||||
| 26 | */ | 26 | */ | ||
| 27 | export function EvidenceTable({ items, prov, showCancer = false, showVariant = true }: { items: EvidenceItem[]; prov: Map<number, ProvRow>; showCancer?: boolean; showVariant?: boolean }) { | 27 | export function EvidenceTable({ items, prov, showCancer = false, showVariant = true }: { items: EvidenceItem[]; prov: Map<number, ProvRow>; showCancer?: boolean; showVariant?: boolean }) { | ||
| 28 | const groups = groupEvidence(items); | 28 | const groups = groupEvidence(items); | ||
| 29 | + // One provenance popover for the whole table (all rows come from one CIViC release); rows carry a compact badge. | ||||
| 30 | + const first = items[0] ? toInfo(prov.get(items[0].provenance_id)) : null; | ||||
| 29 | return ( | 31 | return ( | ||
| 30 | <div className="space-y-6"> | 32 | <div className="space-y-6"> | ||
| 33 | + <p className="flex flex-wrap items-center gap-2 text-[12px] text-ink-3"> | ||||
| 34 | + <SourceBadge p={first ?? { sourceSlug: 'civic', sourceName: 'CIViC' }} /> | ||||
| 35 | + <ClaimBadge kind="curated" /> | ||||
| 36 | + {items.length} evidence item{items.length === 1 ? '' : 's'} · levels, directions and significance as curated at the source; each row links to its CIViC record. | ||||
| 37 | + </p> | ||||
| 31 | {groups.map((g) => ( | 38 | {groups.map((g) => ( | ||
| 32 | <section key={g.key} aria-label={g.label}> | 39 | <section key={g.key} aria-label={g.label}> | ||
| 33 | {showVariant ? ( | 40 | {showVariant ? ( | ||
@@ -131,8 +138,7 @@ export function EvidenceTable({ items, prov, showCancer = false, showVariant = t | |||||
| 131 | </td> | 138 | </td> | ||
| 132 | <td> | 139 | <td> | ||
| 133 | <span className="inline-flex flex-wrap gap-1"> | 140 | <span className="inline-flex flex-wrap gap-1"> | ||
| 134 | − {toInfo(prov.get(e.provenance_id)) ? <SourceBadge p={toInfo(prov.get(e.provenance_id))!} /> : <SourceBadge p={{ sourceSlug: 'civic', sourceName: 'CIViC' }} />} | 141 | + <SourceBadge compact p={toInfo(prov.get(e.provenance_id)) ?? { sourceSlug: 'civic', sourceName: 'CIViC' }} /> | ||
| 135 | − <ClaimBadge kind="curated" /> | ||||
| 136 | </span> | 142 | </span> | ||
| 137 | </td> | 143 | </td> | ||
| 138 | </tr> | 144 | </tr> | ||
modified
apps/web/src/components/ui/source-badge.tsx
+10 −1
@@ -21,7 +21,16 @@ export interface ProvenanceInfo { | |||||
| 21 | * Small source badge; hover / focus reveals the provenance popover (source, dataset, version, | 21 | * Small source badge; hover / focus reveals the provenance popover (source, dataset, version, | ||
| 22 | * retrieved date, raw vs normalized, link). CSS-only so it works inside server components. | 22 | * retrieved date, raw vs normalized, link). CSS-only so it works inside server components. | ||
| 23 | */ | 23 | */ | ||
| 24 | −export function SourceBadge({ p, className = '' }: { p: ProvenanceInfo; className?: string }) { | 24 | +export function SourceBadge({ p, className = '', compact = false }: { p: ProvenanceInfo; className?: string; compact?: boolean }) { | ||
| 25 | + // compact: link only, no popover — for dense tables where every row shares one source/dataset (the | ||||
| 26 | + // popover is then shown once in the table caption). | ||||
| 27 | + if (compact) { | ||||
| 28 | + return ( | ||||
| 29 | + <Link href={`/source/${p.sourceSlug}`} className={`ci-mono inline-flex items-center rounded-sm border border-rule-strong bg-paper px-1 py-[0px] text-[10.5px] leading-4 text-ink-2 no-underline hover:border-accent hover:text-accent focus:border-accent ${className}`} aria-label={`Source: ${p.sourceName ?? p.sourceSlug}`}> | ||||
| 30 | + {p.sourceSlug} | ||||
| 31 | + </Link> | ||||
| 32 | + ); | ||||
| 33 | + } | ||||
| 25 | return ( | 34 | return ( | ||
| 26 | <span className={`ci-pop ${className}`}> | 35 | <span className={`ci-pop ${className}`}> | ||
| 27 | <Link | 36 | <Link | ||
| 28 | 37 | ||||