iris-ir-platform / src /components /chat /SourcesFootnotes.tsx
rajvivan's picture
style: use blue user icon and page badges
f67b939 verified
Raw
History Blame Contribute Delete
4.54 kB
'use client';
import React from 'react';
interface Source {
id: number;
docName: string;
page: number;
support: string;
}
interface SourcesFootnotesProps {
sources: Source[];
onOpenPage: (docName: string, page: number) => void;
}
export function SourcesFootnotes({ sources, onOpenPage }: SourcesFootnotesProps) {
// Group sources by docName
const grouped: Record<string, { pages: number[]; supports: string[] }> = {};
sources.forEach(src => {
const key = src.docName;
if (!grouped[key]) {
grouped[key] = { pages: [], supports: [] };
}
if (!grouped[key].pages.includes(src.page)) {
grouped[key].pages.push(src.page);
}
if (src.support && !grouped[key].supports.includes(src.support)) {
grouped[key].supports.push(src.support);
}
});
const docKeys = Object.keys(grouped);
return (
<div style={{ padding: '1.25rem 1.5rem 1.5rem', borderTop: '1px solid var(--border-subtle)' }}>
{/* Label */}
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: '0.625rem',
}}>
<div className="section-label" style={{ marginBottom: 0 }}>
Sources &amp; Footnotes
</div>
<span style={{ fontSize: '0.65rem', color: 'var(--text-muted)', fontStyle: 'italic' }}>
{sources.length} reference{sources.length !== 1 ? 's' : ''}
</span>
</div>
{/* Footnotes */}
<div className="footnote-list" style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
{docKeys.map((docName, idx) => {
const item = grouped[docName];
const supportText = item.supports[0] || 'Retrieved evidence';
return (
<div key={idx} className="footnote-item">
<div className="footnote-number">{idx + 1}</div>
<div className="footnote-content" style={{ display: 'flex', flexDirection: 'column', gap: '0.15rem' }}>
<div className="footnote-doc" style={{ fontWeight: 600, fontSize: '0.8rem', color: 'var(--text-primary)' }}>
{docName}
</div>
<div className="footnote-support" style={{ fontSize: '0.72rem', color: 'var(--text-muted)', marginBottom: '0.25rem' }}>
{supportText}
</div>
{/* Horizontal link list for pages */}
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: '0.45rem', marginTop: '0.4rem' }}>
{item.pages.map((pageNum) => (
<button
key={pageNum}
onClick={() => onOpenPage(docName, pageNum)}
style={{
background: 'var(--enbd-blue-muted)',
color: 'var(--enbd-blue)',
border: '1px solid var(--enbd-blue-border)',
padding: '0.2rem 0.65rem',
fontSize: '0.68rem',
borderRadius: '20px',
cursor: 'pointer',
fontWeight: 600,
fontFamily: 'var(--font-body)',
display: 'inline-flex',
alignItems: 'center',
gap: '0.25rem',
transition: 'all var(--ease-fast)',
letterSpacing: '0.01em',
}}
onMouseOver={e => {
e.currentTarget.style.background = 'rgba(0, 85, 165, 0.14)';
e.currentTarget.style.boxShadow = '0 0 8px rgba(0, 85, 165, 0.14)';
}}
onMouseOut={e => {
e.currentTarget.style.background = 'var(--enbd-blue-muted)';
e.currentTarget.style.boxShadow = 'none';
}}
>
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
</svg>
Page {pageNum}
</button>
))}
</div>
</div>
</div>
);
})}
</div>
</div>
);
}