Tesseract / studio /src /components /CollapsibleCode.jsx
rkbosamia's picture
fine tuning + base model change
bb15695
Raw
History Blame Contribute Delete
4.21 kB
import { useState, useRef, useEffect } from 'react'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'
import { useCopyToClipboard } from '../hooks/useCopyToClipboard'
const LANG_ALIASES = {
jsx: 'jsx', tsx: 'tsx', js: 'javascript', javascript: 'javascript',
ts: 'typescript', typescript: 'typescript',
py: 'python', python: 'python', css: 'css', json: 'json',
html: 'markup', sh: 'bash', bash: 'bash',
}
function ChevronIcon({ open }) {
return (
<svg
width="11"
height="11"
viewBox="0 0 16 16"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
style={{
transform: open ? 'rotate(90deg)' : 'rotate(0deg)',
transition: 'transform 120ms ease',
}}
>
<path d="M6 4l4 4-4 4" />
</svg>
)
}
function StreamingDots() {
return (
<span className="inline-flex items-center gap-1 ml-1">
{[0, 150, 300].map(d => (
<span
key={d}
className="w-1 h-1 rounded-full animate-bounce"
style={{ background: 'currentColor', animationDelay: `${d}ms` }}
/>
))}
</span>
)
}
export default function CollapsibleCode({ filename, lang, code, streaming }) {
// Auto-expand while streaming so the user can watch live; collapse when done.
const [expanded, setExpanded] = useState(false)
const wasStreaming = useRef(streaming)
const codeRef = useRef(null)
// Collapse the moment streaming finishes (auto-close polish).
useEffect(() => {
if (wasStreaming.current && !streaming) {
setExpanded(false)
}
wasStreaming.current = streaming
}, [streaming])
// Auto-scroll the code panel to the bottom while it's streaming and expanded.
useEffect(() => {
if (streaming && expanded && codeRef.current) {
codeRef.current.scrollTop = codeRef.current.scrollHeight
}
}, [code, streaming, expanded])
const { copied, copy } = useCopyToClipboard()
const language = LANG_ALIASES[(lang || '').toLowerCase()] || 'text'
const label = streaming ? 'Writing' : 'Wrote'
const accent = streaming ? 'var(--accent-hi)' : 'var(--text-dim)'
return (
<div
className="my-2 rounded-lg overflow-hidden border"
style={{ borderColor: 'var(--border)', background: 'var(--surface-2)' }}
>
<button
onClick={() => setExpanded(e => !e)}
className="w-full flex items-center gap-2 px-3 py-2 text-left transition-colors"
style={{ background: 'var(--surface-3)', color: 'var(--text-dim)' }}
>
<span style={{ color: accent }}>
<ChevronIcon open={expanded} />
</span>
<span className="text-[12px]" style={{ color: accent }}>{label}</span>
<span className="mono text-[12px]" style={{ color: 'var(--text)' }}>{filename}</span>
{streaming && <span style={{ color: accent }}><StreamingDots /></span>}
<span className="flex-1" />
{!streaming && (
<span
onClick={(e) => { e.stopPropagation(); copy(code, 'Code copied') }}
className="text-[11px] mono px-2 py-0.5 rounded hover:bg-[var(--surface)] transition-colors"
style={{ color: copied ? 'var(--accent-hi)' : 'var(--text-faint)' }}
>
{copied ? 'copied' : 'copy'}
</span>
)}
</button>
{expanded && (
<div
ref={codeRef}
style={{ maxHeight: 360, overflow: 'auto', background: 'var(--surface-2)' }}
>
<SyntaxHighlighter
language={language}
style={oneDark}
customStyle={{
margin: 0,
padding: '12px 14px',
background: 'var(--surface-2)',
fontSize: 12.5,
lineHeight: 1.55,
fontFamily: "'JetBrains Mono', ui-monospace, monospace",
}}
codeTagProps={{ style: { fontFamily: "'JetBrains Mono', ui-monospace, monospace" } }}
wrapLongLines
>
{code || ''}
</SyntaxHighlighter>
</div>
)}
</div>
)
}