'use client' import * as React from 'react' import { cn } from '@/lib/utils' export type TerminalLineType = 'input' | 'output' | 'warn' | 'error' | 'system' export interface TerminalLine { type?: TerminalLineType text: string timestamp?: string } export interface TerminalProps extends React.HTMLAttributes { lines?: TerminalLine[] prompt?: string title?: string height?: string | number blinkCursor?: boolean } function lineColor(type: TerminalLineType = 'output'): string { switch (type) { case 'input': return 'var(--color-green)' case 'output': return 'var(--text-secondary)' case 'warn': return 'var(--color-amber)' case 'error': return 'var(--color-red)' case 'system': return 'var(--text-muted)' } } function linePrefix(type: TerminalLineType = 'output'): string { switch (type) { case 'input': return '>' case 'output': return ' ' case 'warn': return '⚠' case 'error': return '✕' case 'system': return '#' } } const Terminal = React.forwardRef( ( { className, lines = [], prompt = '>', title = 'TERMINAL', height = '16rem', blinkCursor = true, style, ...props }, ref ) => { const bodyRef = React.useRef(null) React.useEffect(() => { if (bodyRef.current) { bodyRef.current.scrollTop = bodyRef.current.scrollHeight } }, [lines]) return (
{/* Title bar */}
{title} {/* Status dot */}
{/* Output body */}
{lines.map((line, i) => (
{line.timestamp && ( {line.timestamp} )} {linePrefix(line.type)} {line.text}
))} {/* Blinking cursor */} {blinkCursor && (
{prompt}
)}
) } ) Terminal.displayName = 'Terminal' export { Terminal }