HTML 77.2%
TypeScript 10.5%
Python 9.6%
JavaScript 2.5%
1'use client';2import { createContext, type ReactNode, useCallback, useContext, useEffect, useMemo, useState } from 'react';3import type { ProvenanceEntry } from '@/lib/types';45/** What the drawer needs to explain one displayed value. `fallback` = the inline provenance the caller already has. */6export interface EvidenceTarget {7 slug: string;8 property: string;9 /** The displayed value (raw) — formatted in the drawer with `fmtValue(value, property)` unless `display` is given. */10 value?: unknown;11 display?: string;12 unit?: string | null;13 label?: string;14 fallback?: ProvenanceEntry | null;15 entity?: { name?: string; entity_type?: string } | null;16}1718interface Ctx {19 target: EvidenceTarget | null;20 open: (t: EvidenceTarget) => void;21 close: () => void;22}23const EvidenceCtx = createContext<Ctx>({ target: null, open: () => undefined, close: () => undefined });2425const HASH_RE = /^#evidence=([^:]+):(.+)$/;2627/** Mounted once in the root layout. Mirrors the open target to `#evidence=<slug>:<property>` so a drawer can be linked. */28export function EvidenceProvider({ children }: { children: ReactNode }) {29 const [target, setTarget] = useState<EvidenceTarget | null>(null);30 const open = useCallback((t: EvidenceTarget) => {31 setTarget(t);32 try {33 history.replaceState(null, '', `#evidence=${encodeURIComponent(t.slug)}:${encodeURIComponent(t.property)}`);34 } catch {35 /* ignore */36 }37 }, []);38 const close = useCallback(() => {39 setTarget(null);40 try {41 if (HASH_RE.test(location.hash)) history.replaceState(null, '', location.pathname + location.search);42 } catch {43 /* ignore */44 }45 }, []);46 useEffect(() => {47 const m = HASH_RE.exec(location.hash);48 if (m) setTarget({ slug: decodeURIComponent(m[1] as string), property: decodeURIComponent(m[2] as string) });49 }, []);50 const value = useMemo(() => ({ target, open, close }), [target, open, close]);51 return <EvidenceCtx.Provider value={value}>{children}</EvidenceCtx.Provider>;52}5354export function useEvidence(): Ctx {55 return useContext(EvidenceCtx);56}57