| 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', |
| sh: 'bash', shell: 'bash', bash: 'bash', zsh: 'bash', |
| html: 'markup', xml: 'markup', svg: 'markup', |
| css: 'css', json: 'json', yaml: 'yaml', yml: 'yaml', |
| sql: 'sql', md: 'markdown', markdown: 'markdown', |
| } |
|
|
| export default function CodeBlock({ lang, children, dense = false }) { |
| const code = String(children || '').replace(/\n$/, '') |
| const language = LANG_ALIASES[(lang || '').toLowerCase()] || 'text' |
| const { copied, copy } = useCopyToClipboard() |
|
|
| return ( |
| <div className="relative group my-2 rounded-lg overflow-hidden border" style={{ borderColor: 'var(--border)' }}> |
| <div |
| className="flex items-center justify-between px-3 py-1.5 text-[10px] uppercase tracking-wider" |
| style={{ background: 'var(--surface-3)', color: 'var(--text-faint)' }} |
| > |
| <span className="mono">{language === 'text' ? 'code' : language}</span> |
| <button |
| onClick={() => copy(code, 'Code copied')} |
| className="text-[var(--text-dim)] hover:text-[var(--text)] transition-colors flex items-center gap-1" |
| title="Copy code" |
| > |
| {copied ? ( |
| <> |
| <svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"> |
| <path d="M3 8.5l3.5 3.5L13 4.5" /> |
| </svg> |
| copied |
| </> |
| ) : ( |
| <> |
| <svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"> |
| <rect x="4" y="4" width="9" height="9" rx="1.5" /> |
| <path d="M3 11V3.5A1.5 1.5 0 0 1 4.5 2H11" /> |
| </svg> |
| copy |
| </> |
| )} |
| </button> |
| </div> |
| <SyntaxHighlighter |
| language={language} |
| style={oneDark} |
| showLineNumbers={false} |
| customStyle={{ |
| margin: 0, |
| padding: dense ? '10px 12px' : '14px 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> |
| ) |
| } |
|
|