import * as React from "react" import { terminalThemeClass, terminalThemeLightClass, type TerminalTheme, } from "@/lib/terminal-themes" import { cn } from "@/lib/utils" import { TerminalBodyScroll } from "./terminal-body-scroll" export type { TerminalTheme } from "@/lib/terminal-themes" export type TerminalProgressConfig = { value: number /** Label beside the bar — e.g. "context". */ label?: React.ReactNode /** Show the numeric percentage after the bar. Defaults to false when label is set. */ showValue?: boolean } export type TerminalProgress = number | TerminalProgressConfig | false function resolveProgress(progress: TerminalProgress | undefined) { if (progress === false || progress === undefined) return null if (typeof progress === "number") { return { value: progress, label: undefined, showValue: true } } return { value: progress.value, label: progress.label, showValue: progress.showValue ?? progress.label == null, } } export type TerminalBodyProps = React.HTMLAttributes & { footer?: React.ReactNode header?: React.ReactNode /** Stretch to fill a fixed-height window and scroll internally. Defaults to content-height flow. */ fill?: boolean pinScrollBottom?: boolean } function TerminalBodyLayout({ className, children, footer, header, fill = false, pinScrollBottom = false, ...props }: TerminalBodyProps) { return (
{header ? (
{header}
) : null}
{children}
{footer ? (
{footer}
) : null}
) } export type TerminalWindowProps = React.HTMLAttributes & { path?: string /** Pass `false` to hide the header progress indicator. */ progress?: TerminalProgress showTrafficLights?: boolean /** Built-in palette — default, grok, or claude. */ theme?: TerminalTheme variant?: "dark" | "light" footer?: React.ReactNode header?: React.ReactNode /** Stretch to fill a fixed-height window and scroll internally. */ fill?: boolean pinScrollBottom?: boolean /** Classes for the inner body layout wrapper. */ bodyClassName?: string /** Optional control rendered at the end of the window chrome header. */ headerAction?: React.ReactNode } export function TerminalWindow({ path, progress, showTrafficLights = true, theme = "default", variant = "dark", className, children, style, footer, header, fill = false, pinScrollBottom = false, bodyClassName, headerAction, ...props }: TerminalWindowProps) { const resolvedProgress = resolveProgress(progress) return (
{(path || resolvedProgress || showTrafficLights || headerAction) && ( )} {children}
) } /** @deprecated Pass footer, header, fill, and pinScrollBottom to TerminalWindow instead. */ export function TerminalBody(props: TerminalBodyProps) { return } export type TerminalHeaderProps = { path?: string progress?: { value: number label?: React.ReactNode showValue: boolean } showTrafficLights?: boolean className?: string headerAction?: React.ReactNode /** @default true */ showBorderBottom?: boolean } function TerminalHeaderProgress({ progress, label, showValue, }: { progress: number label?: React.ReactNode showValue: boolean }) { const ariaLabel = label != null && label !== "" ? String(label) : "Progress" return (
| {label ? ( {label} ) : null} {showValue ? ( {progress.toFixed(2)}% ) : null}
) } export function TerminalHeader({ path, progress, showTrafficLights = true, className, headerAction, showBorderBottom = true, }: TerminalHeaderProps) { return (
{showTrafficLights && (
)} {path && (
{path}
)} {progress && ( )} {headerAction ?
{headerAction}
: null}
) } export type TerminalStatusBarProps = React.HTMLAttributes & { left?: React.ReactNode right?: React.ReactNode } export function TerminalStatusBar({ left, right, className, children, ...props }: TerminalStatusBarProps) { return (
{left ?? children}
{right &&
{right}
}
) }