SPB Git

spb/cancerindex

Public

Web: single provenance popover per evidence table, compact row badges

Simon-Pierre Boucher committed (Sep 8, 2026) parent 36d464d Browse files

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
Menu

Theme