File size: 2,892 Bytes
5e17e07 6c0127c 5e17e07 6c0127c 5e17e07 6c0127c 5e17e07 6c0127c 5e17e07 6c0127c 5e17e07 6c0127c 5e17e07 6c0127c 5e17e07 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | import { useState } from 'react';
interface ResultCardProps {
title: string;
score: number;
snippet: string;
expanded?: boolean;
onToggle?: () => void;
}
function ScoreBadge({ score }: { score: number }) {
const pct = Math.round(score * 100);
const bg = pct >= 80 ? 'var(--score-good-bg)' : pct >= 50 ? 'var(--score-mid-bg)' : 'var(--score-bad-bg)';
const color = pct >= 80 ? '#2e7d32' : pct >= 50 ? '#f57f17' : 'var(--text-secondary)';
return (
<span style={{
display: 'inline-block',
padding: '0.15rem 0.45rem',
borderRadius: '4px',
background: bg,
color,
fontFamily: "'SF Mono', 'Fira Code', 'Cascadia Code', monospace",
fontSize: '0.72rem',
fontWeight: 700,
}}>
{pct}%
</span>
);
}
export default function ResultCard({ title, score, snippet, expanded: expandedProp, onToggle }: ResultCardProps) {
const [localExpanded, setLocalExpanded] = useState(false);
const isControlled = expandedProp !== undefined;
const expanded = isControlled ? expandedProp : localExpanded;
function handleToggle() {
if (isControlled) {
onToggle?.();
} else {
setLocalExpanded(e => !e);
}
}
const preview = snippet.length > 200 ? snippet.slice(0, 200) + '\u2026' : snippet;
return (
<div
onClick={handleToggle}
style={{
padding: '0.65rem 0.85rem',
background: 'var(--bg-card)',
border: '1px solid var(--border)',
borderRadius: '6px',
marginBottom: '0.4rem',
cursor: 'pointer',
transition: 'box-shadow 0.15s',
}}
onMouseEnter={e => { (e.currentTarget as HTMLDivElement).style.boxShadow = '0 2px 8px var(--shadow)'; }}
onMouseLeave={e => { (e.currentTarget as HTMLDivElement).style.boxShadow = 'none'; }}
>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '0.5rem' }}>
<span style={{
fontFamily: 'system-ui, -apple-system, sans-serif',
fontSize: '0.85rem',
fontWeight: 600,
color: 'var(--text)',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
flex: 1,
}}>
{title}
</span>
<ScoreBadge score={score} />
<span style={{ color: 'var(--text-muted)', fontSize: '0.75rem', flexShrink: 0 }}>
{expanded ? '\u25B2' : '\u25BC'}
</span>
</div>
<div style={{
marginTop: '0.4rem',
fontFamily: "'SF Mono', 'Fira Code', 'Cascadia Code', monospace",
fontSize: '0.72rem',
color: 'var(--text-secondary)',
lineHeight: 1.5,
whiteSpace: expanded ? 'pre-wrap' : 'nowrap',
overflow: 'hidden',
textOverflow: expanded ? 'unset' : 'ellipsis',
}}>
{expanded ? snippet : preview}
</div>
</div>
);
}
|