import type { ReactElement, CSSProperties } from "react"; export interface TerminalLine { type: "prompt" | "command" | "output" | "error" | "warning" | "success"; content: string; } export interface TerminalTab { id: string; label: string; } export interface TerminalPanelProps { open: boolean; onClose: () => void; tabs?: TerminalTab[]; activeTab?: string; onTabChange?: (id: string) => void; lines?: TerminalLine[]; className?: string; } const defaultTabs: TerminalTab[] = [ { id: "main", label: "main" }, { id: "build", label: "build" }, { id: "logs", label: "logs" }, ]; const blinkKeyframes = ` @keyframes ms-terminal-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } } `; let blinkStyleInjected = false; function ensureBlinkStyle(): void { if (blinkStyleInjected || typeof document === "undefined") return; const styleEl = document.createElement("style"); styleEl.textContent = blinkKeyframes; document.head.appendChild(styleEl); blinkStyleInjected = true; } function getLineColor(type: TerminalLine["type"]): string { switch (type) { case "prompt": return "var(--success)"; case "command": return "var(--text-2)"; case "output": return "var(--muted)"; case "error": return "var(--danger)"; case "warning": return "var(--warn)"; case "success": return "var(--success)"; default: return "var(--muted)"; } } export function TerminalPanel({ open, onClose, tabs, activeTab, onTabChange, lines = [], className = "", }: TerminalPanelProps): ReactElement { ensureBlinkStyle(); const resolvedTabs = tabs ?? defaultTabs; const resolvedActiveTab = activeTab ?? resolvedTabs[0]?.id ?? ""; const panelStyle: CSSProperties = { background: "var(--bg-deep)", borderTop: "1px solid var(--border)", overflow: "hidden", flexShrink: 0, display: "flex", flexDirection: "column", height: open ? 280 : 0, transition: "height 0.3s ease", }; const headerStyle: CSSProperties = { display: "flex", alignItems: "center", gap: 10, padding: "6px 16px", borderBottom: "1px solid var(--border)", flexShrink: 0, }; const tabBarStyle: CSSProperties = { display: "flex", gap: 2, }; const actionsStyle: CSSProperties = { marginLeft: "auto", display: "flex", gap: 4, }; const bodyStyle: CSSProperties = { flex: 1, overflowY: "auto", padding: "10px 16px", fontFamily: "var(--mono)", fontSize: "0.78rem", lineHeight: 1.6, }; const cursorStyle: CSSProperties = { display: "inline-block", width: 7, height: 14, background: "var(--success)", marginLeft: 2, animation: "ms-terminal-blink 1s step-end infinite", verticalAlign: "text-bottom", }; return (