import * as React from "react"; import { useEffect, useRef } from "react"; import { cn } from "../lib/utils"; export interface TerminalDisplayProps extends React.HTMLAttributes { variant?: "default" | "sandbox"; title?: string; showHeader?: boolean; autoScroll?: boolean; maxHeight?: string; } const TerminalDisplay = React.forwardRef( ( { className, variant = "default", title = "Terminal", showHeader = true, autoScroll = true, maxHeight = "400px", children, ...props }, ref, ) => { const containerRef = useRef(null); useEffect(() => { if (autoScroll && containerRef.current) { containerRef.current.scrollTop = containerRef.current.scrollHeight; } }, [autoScroll]); const variants = { default: "border-border", sandbox: "border-border shadow-[var(--shadow-accent)]", }; return (
{showHeader && (
{title}
)}
{children}
); }, ); TerminalDisplay.displayName = "TerminalDisplay"; export interface TerminalLineProps extends React.HTMLAttributes { type?: | "input" | "output" | "error" | "success" | "info" | "thinking" | "command" | "warning"; prompt?: string; timestamp?: string; } const TerminalLine = React.forwardRef( ( { className, type = "output", prompt = "$", timestamp, children, ...props }, ref, ) => { const typeStyles = { input: "text-foreground", output: "text-foreground", error: "text-[var(--surface-danger-text)]", success: "text-[var(--surface-success-text)]", info: "text-[var(--surface-info-text)]", thinking: "text-[var(--surface-warning-text)] animate-pulse", command: "text-foreground", warning: "text-[var(--surface-warning-text)]", }; return (
{(type === "input" || type === "command") && ( {prompt} )} {type === "thinking" && ( ... )} {timestamp && ( [{timestamp}] )} {children}
); }, ); TerminalLine.displayName = "TerminalLine"; const TerminalCursor = React.forwardRef< HTMLSpanElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( )); TerminalCursor.displayName = "TerminalCursor"; export interface TerminalInputProps extends Omit, "onSubmit"> { onSubmit?: (value: string) => void; variant?: "default" | "sandbox"; } const TerminalInput = React.forwardRef( ({ className, onSubmit, variant = "default", ...props }, ref) => { const [value, setValue] = React.useState(""); const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter" && value.trim() && onSubmit) { onSubmit(value.trim()); setValue(""); } }; const variants = { default: "border-border focus-within:border-border", sandbox: "border-border focus-within:border-[var(--border-accent-hover)]", }; return (
$ setValue(e.target.value)} onKeyDown={handleKeyDown} className="flex-1 bg-transparent text-foreground outline-none placeholder:text-muted-foreground" {...props} />
); }, ); TerminalInput.displayName = "TerminalInput"; export { TerminalDisplay, TerminalLine, TerminalCursor, TerminalInput };