Superscript citation markers with a compact source footer.
type CiteRef = { n: number; label: string; host: string; url: string };
const TEXT =
"Transformers scale well with data and compute[1], though attention is quadratic in sequence length[2].";
const REFS: CiteRef[] = [
{ n: 1, label: "Vaswani et al.", host: "arxiv.org", url: "https://arxiv.org/abs/1706.03762" },
{ n: 2, label: "Tay et al.", host: "arxiv.org", url: "https://arxiv.org/abs/2009.06732" },
];
function CiteArrow() {
return (
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
<path d="M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18" />
</svg>
);
}
export function InlineCitations({
text = TEXT,
refs = REFS,
}: {
text?: string;
refs?: CiteRef[];
}) {
// Markers like [1] in the text become small numbered chips that link to
// the source and reveal the reference name in a tooltip on hover.
const parts = text.split(/(\[\d+\])/g);
return (
<div className="cite-prose">
<p>
{parts.map((part, i) => {
const m = part.match(/^\[(\d+)\]$/);
if (!m) return <span key={i}>{part}</span>;
const r = refs.find((x) => x.n === Number(m[1]));
return r ? (
<span key={i} className="cite-tip">
<a className="cite-mark" href={r.url} target="_blank" rel="noreferrer">{r.n}</a>
<span className="cite-tip-box" role="tooltip">{r.label}</span>
</span>
) : (
<span key={i} className="cite-mark">{m[1]}</span>
);
})}
</p>
<div className="cite-footer">
{refs.map((r) => (
<a key={r.n} className="cite-ref" href={r.url} target="_blank" rel="noreferrer">
<span className="cite-mark">{r.n}</span>
<span className="cite-ref-label">{r.label}</span>
<span className="cite-sep">·</span>
<span className="cite-ref-host">{r.host}</span>
<span className="cite-arrow" aria-hidden><CiteArrow /></span>
</a>
))}
</div>
</div>
);
}
/* InlineCitations.css */
.cite-prose { font-size: 14px; line-height: 1.5; color: #1a1a1a; }
.cite-prose p { margin: 0; }
.cite-mark { display: inline-flex; align-items: center; justify-content: center; width: 12px; height: 12px; flex: none; border-radius: 4px; background: #f4f5f7; color: #a1a1a1; font-size: 9px; font-weight: 600; line-height: 1; vertical-align: 5.5px; margin: 0 2px; }
a.cite-mark { cursor: pointer; text-decoration: none; transition: color 0.15s, background 0.15s; }
a.cite-mark:hover { color: #1a1a1a; background: #e6e8ec; }
.cite-tip { position: relative; display: inline; }
.cite-tip-box { position: absolute; left: 50%; bottom: calc(100% + 6px); transform: translateX(-50%) translateY(1px); font-size: 10px; line-height: 1; font-weight: 500; color: rgba(255, 255, 255, 0.9); background: rgba(29, 29, 29, 0.6); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); padding: 4px 5px; border-radius: 6px; white-space: nowrap; pointer-events: none; opacity: 0; filter: blur(2px); transition: opacity 0.15s ease, transform 0.15s ease, filter 0.15s ease; z-index: 1000; }
.cite-tip:hover .cite-tip-box, .cite-tip:focus-within .cite-tip-box { opacity: 1; filter: blur(0); transform: translateX(-50%) translateY(0); }
.cite-footer { display: flex; flex-direction: column; gap: 6px; margin-top: 12px; padding-top: 10px; border-top: 1px solid #e6e8ec; }
.cite-ref { display: flex; align-items: center; gap: 6px; font-size: 12px; line-height: 18px; color: #a1a1a1; min-width: 0; text-decoration: none; cursor: pointer; }
.cite-ref .cite-mark { margin: 0; }
.cite-ref-label { color: #1a1a1a; font-weight: 450; white-space: nowrap; flex: none; }
.cite-sep { color: #a1a1a1; flex: none; }
.cite-ref-host { color: #a1a1a1; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; transition: color 0.16s; }
.cite-arrow { display: inline-flex; flex: none; margin-left: -2px; color: #a1a1a1; opacity: 0; transform: rotate(45deg) translate(0, 2px); transition: opacity 0.16s, transform 0.22s; pointer-events: none; }
.cite-ref:hover .cite-arrow { opacity: 1; transform: rotate(45deg) translate(0, 0); }
.cite-ref:hover .cite-ref-host { color: #1a1a1a; }
@media (prefers-color-scheme: dark) {
.cite-prose { color: #f5f5f5; }
.cite-mark { background: #424242; }
a.cite-mark:hover { color: #f5f5f5; background: #525252; }
.cite-footer { border-top-color: #303030; }
.cite-ref-label { color: #f5f5f5; }
.cite-ref:hover .cite-ref-host { color: #f5f5f5; }
}