diff --git a/app/playground/page.tsx b/app/playground/page.tsx index f6a7bde..f1ec138 100644 --- a/app/playground/page.tsx +++ b/app/playground/page.tsx @@ -1,5 +1,15 @@ import { TerminalApp } from '@/components/terminal-app' -import { Terminal, TerminalCommand, TerminalDiff, TerminalOutput, TerminalSpinner, TerminalBadge, ThemeSwitcher } from '@/components/terminal' +import { + Terminal, + TerminalCommand, + TerminalDiff, + TerminalOutput, + TerminalSpinner, + TerminalBadge, + TerminalMarker, + TerminalLogLine, + ThemeSwitcher, +} from '@/components/terminal' import { TerminalProgress } from '@/components/terminal-progress' import { LogDemo } from './log-demo' import { PromptDemo } from './prompt-demo' @@ -14,25 +24,19 @@ export default function PlaygroundPage() { return (
-

- Playground -

+

Playground

-

- Terminal App -

+

Terminal App

-

- TerminalPrompt -

+

TerminalPrompt

Interactive command input with history navigation (up / down).

@@ -40,9 +44,7 @@ export default function PlaygroundPage() {
-

- TerminalProgress -

+

TerminalProgress

pnpm install @@ -53,9 +55,7 @@ export default function PlaygroundPage() {
-

- TerminalSpinner -

+

TerminalSpinner

pnpm run build @@ -63,9 +63,7 @@ export default function PlaygroundPage() {
-

- TerminalLog -

+

TerminalLog

Simulated streaming logs with capped history and auto-scroll.

@@ -73,20 +71,18 @@ export default function PlaygroundPage() {
-

- Copy Button -

+

Copy Button

pnpm run build Compiled successfully in 1.2s - Click the copy icon in the header to copy this output. + + Click the copy icon in the header to copy this output. +
-

- TerminalDiff -

+

TerminalDiff

git diff -- src/config.ts Unified @@ -124,9 +120,7 @@ export default function PlaygroundPage() {
-

- TerminalTree -

+

TerminalTree

Expandable tree with custom icon, label, and row render props.

@@ -138,16 +132,14 @@ export default function PlaygroundPage() { Tree Keyboard Navigation

- Arrow keys to navigate, Enter/Space to toggle, ArrowRight to expand/enter, ArrowLeft to collapse/parent. + Arrow keys to navigate, Enter/Space to toggle, ArrowRight to expand/enter, ArrowLeft to + collapse/parent.

-
-

- TerminalBadge -

+

TerminalBadge

pnpm run release @@ -162,9 +154,85 @@ export default function PlaygroundPage() {
-

- Typing Animation -

+

TerminalMarker

+

+ Phase separators for visual boundaries in terminal feeds. +

+ + npm run deploy:full + + ✓ Compiled 42 modules + dist/main.js 124 KB + + ✓ 24 tests passed + coverage: 94% + + → Deploying to production... + ✓ Deployed successfully + + +
+ +
+

TerminalLogLine

+

+ Structured log row primitive with level badge, timestamp, source, and message. +

+ + pnpm run start + + + + + + + + + +
+ +
+

Typing Animation

npm run deploy diff --git a/components/terminal-log-line.tsx b/components/terminal-log-line.tsx new file mode 100644 index 0000000..c82d751 --- /dev/null +++ b/components/terminal-log-line.tsx @@ -0,0 +1,124 @@ +'use client' + +import { ReactNode } from 'react' + +export interface TerminalLogLineProps { + /** Primary log message content. */ + message: ReactNode + /** Severity level — controls the label color (default: 'info'). */ + level?: 'debug' | 'info' | 'warn' | 'error' | 'success' + /** Optional timestamp string (e.g. "10:23:45" or ISO). */ + timestamp?: string + /** Optional source / subsystem label (e.g. "server", "db"). */ + source?: string + /** Additional classes for layout overrides. */ + className?: string +} + +/** + * Per-level color tokens — border, background tint, and text colors. + * + * `badge` — the [LEVEL] indicator pill (border + bg tint, consistent with TerminalBadge) + * `message` — foreground for the message body (dimmed for debug, red for error) + */ +const levelClasses: Record< + NonNullable, + { badge: string; message: string } +> = { + debug: { + badge: 'border-(--glass-border) text-(--term-fg-dim) bg-[rgba(255,255,255,0.03)]', + message: 'text-(--term-fg-dim)', + }, + info: { + badge: + 'border-[var(--term-blue)]/40 text-(--term-blue) bg-[color-mix(in_oklab,var(--term-blue)_10%,transparent)]', + message: 'text-(--term-fg)', + }, + warn: { + badge: + 'border-[var(--term-yellow)]/40 text-(--term-yellow) bg-[color-mix(in_oklab,var(--term-yellow)_10%,transparent)]', + message: 'text-(--term-fg)', + }, + error: { + badge: + 'border-[var(--term-red)]/40 text-(--term-red) bg-[color-mix(in_oklab,var(--term-red)_10%,transparent)]', + message: 'text-(--term-red)', + }, + success: { + badge: + 'border-[var(--term-green)]/40 text-(--term-green) bg-[color-mix(in_oklab,var(--term-green)_10%,transparent)]', + message: 'text-(--term-fg)', + }, +} + +/** + * 3-character uppercase level labels. + * All entries are exactly 3 chars so the badge pill stays a consistent width + * across levels in a monospace font. + */ +const levelLabel: Record, string> = { + debug: 'DBG', + info: 'INF', + warn: 'WRN', + error: 'ERR', + success: 'OK', +} + +/** + * A single structured log row primitive for terminal-style feeds. + * + * Renders a monospace row with an optional timestamp, a compact level badge, + * an optional source label, and the log message. All color tokens are derived + * from CSS custom properties, making the component fully theme-aware. + * + * Layout (left → right): + * ``` + * [timestamp] [LVL] source message + * ``` + * + * @param message - Log message body (string or any React node) + * @param level - Severity (debug | info | warn | error | success); default 'info' + * @param timestamp - Optional timestamp string shown in dim foreground + * @param source - Optional subsystem / service label shown after the badge + * @param className - Additional CSS classes + * + * @example + * ```tsx + * + * + * + * + * + * ``` + */ +export function TerminalLogLine({ + message, + level = 'info', + timestamp, + source, + className = '', +}: TerminalLogLineProps) { + const cls = levelClasses[level] + + return ( +
+ {/* Timestamp */} + {timestamp && {timestamp}} + + {/* Level badge — fixed width keeps columns aligned in monospace feeds */} + + {levelLabel[level]} + + + {/* Source */} + {source && {source}} + + {/* Message */} + {message} +
+ ) +} diff --git a/components/terminal-marker.tsx b/components/terminal-marker.tsx new file mode 100644 index 0000000..bc44621 --- /dev/null +++ b/components/terminal-marker.tsx @@ -0,0 +1,92 @@ +'use client' + +export interface TerminalMarkerProps { + /** Label text displayed as the phase marker. */ + label: string + /** Optional timestamp to display after the label. */ + timestamp?: string + /** Visual style variant (default: 'neutral'). */ + variant?: 'info' | 'success' | 'warning' | 'error' | 'neutral' + /** Additional classes for layout tweaks. */ + className?: string +} + +/** + * Per-variant Tailwind classes for border, background tint, label, and timestamp. + * Background tints use `color-mix` for consistent translucency across themes. + */ +const variantClasses: Record< + NonNullable, + { root: string; label: string; timestamp: string } +> = { + neutral: { + root: 'border-[var(--glass-border)] bg-[rgba(255,255,255,0.03)]', + label: 'text-[var(--term-fg)]', + timestamp: 'text-[var(--term-fg-dim)]', + }, + info: { + root: 'border-[var(--term-blue)]/40 bg-[color-mix(in_oklab,var(--term-blue)_8%,transparent)]', + label: 'text-[var(--term-blue)]', + timestamp: 'text-[var(--term-blue)]/60', + }, + success: { + root: 'border-[var(--term-green)]/40 bg-[color-mix(in_oklab,var(--term-green)_8%,transparent)]', + label: 'text-[var(--term-green)]', + timestamp: 'text-[var(--term-green)]/60', + }, + warning: { + root: 'border-[var(--term-yellow)]/40 bg-[color-mix(in_oklab,var(--term-yellow)_8%,transparent)]', + label: 'text-[var(--term-yellow)]', + timestamp: 'text-[var(--term-yellow)]/60', + }, + error: { + root: 'border-[var(--term-red)]/40 bg-[color-mix(in_oklab,var(--term-red)_8%,transparent)]', + label: 'text-[var(--term-red)]', + timestamp: 'text-[var(--term-red)]/60', + }, +} + +/** + * Displays a terminal-style phase separator for visual boundaries in feeds. + * Used to mark different phases like "Build", "Test", "Deploy" in sequential outputs. + * + * Renders a left-bordered row with a semantic background tint, a bold phase label, + * and an optional timestamp. Fully theme-aware via CSS custom properties and + * naturally responsive at any width. + * + * @param label - Phase label text (e.g., "Build", "Test", "Deploy") + * @param timestamp - Optional timestamp to display after the label + * @param variant - Visual style for semantic coloring (default: 'neutral') + * @param className - Additional CSS classes for layout overrides + * + * @example + * ```tsx + * + * + * + * + * ``` + */ +export function TerminalMarker({ + label, + timestamp, + variant = 'neutral', + className = '', +}: TerminalMarkerProps) { + const cls = variantClasses[variant] + + return ( +
+ + {label} + + {timestamp && ( + {timestamp} + )} +
+ ) +} diff --git a/components/terminal.tsx b/components/terminal.tsx index 56c9e1f..cafad15 100644 --- a/components/terminal.tsx +++ b/components/terminal.tsx @@ -18,12 +18,12 @@ const TerminalPromptContext = createContext('$') /** * Displays a terminal window with macOS-style chrome and content area. * Renders a terminal emulator UI with title bar, window controls, and monospace content. - * + * * @param children - Terminal content (TerminalCommand, TerminalOutput, TerminalSpinner components) * @param title - Window title shown in the chrome (default: 'Terminal') * @param prompt - Command prompt symbol (default: '$') * @param className - Additional CSS classes to apply to the container - * + * * @example * ```tsx * @@ -32,7 +32,12 @@ const TerminalPromptContext = createContext('$') * * ``` */ -export function Terminal({ children, title = 'Terminal', prompt = '$', className = '' }: TerminalProps) { +export function Terminal({ + children, + title = 'Terminal', + prompt = '$', + className = '', +}: TerminalProps) { const contentRef = useRef(null) const timeoutRef = useRef | null>(null) const [copied, setCopied] = useState(false) @@ -60,7 +65,9 @@ export function Terminal({ children, title = 'Terminal', prompt = '$', className } return ( -
+
{/* Window Chrome */}
@@ -68,9 +75,7 @@ export function Terminal({ children, title = 'Terminal', prompt = '$', className
-
- {title} -
+
{title}
- + {/* Terminal Content */} -
+
{children}
@@ -98,10 +106,10 @@ interface TerminalCommandProps { * Displays a command line in the terminal with a prompt symbol. * Renders text with a leading prompt indicator (typically '$' or '#'). * Inherits prompt from parent Terminal component via context if not specified. - * + * * @param children - The command text to display * @param prompt - The prompt symbol to display before the command (inherited from Terminal if omitted) - * + * * @example * ```tsx * ls -la @@ -134,13 +142,13 @@ interface TerminalOutputProps { * Displays output text with semantic coloring based on message type. * Uses theme colors to indicate success (green), error (red), info (blue), or warning (yellow). * Supports optional typing animation for string children and Prism.js syntax highlighting. - * + * * @param children - The output text to display * @param type - The type of output message (default: 'normal') * @param animate - Enable typing animation (default: false) * @param delay - Milliseconds per character when animating (default: 35) * @param language - Language for syntax highlighting (e.g. 'json', 'typescript') - * + * * @example * ```tsx * Build completed successfully @@ -207,7 +215,11 @@ export function TerminalOutput({
{highlightedHtml ? ( - ) : animate && textContent !== null ? typedText : children} + ) : animate && textContent !== null ? ( + typedText + ) : ( + children + )}
) } @@ -219,9 +231,9 @@ interface TerminalSpinnerProps { /** * Displays an animated spinner with optional text for loading states. * Uses Unicode braille characters for smooth animation. - * + * * @param text - Optional text to display next to the spinner - * + * * @example * ```tsx * @@ -260,7 +272,17 @@ export { TerminalAlert } from './terminal-alert' export { TerminalTabs } from './terminal-tabs' export { TerminalSplit } from './terminal-split' export { TerminalDiff } from './terminal-diff' -export { TerminalAutocomplete, useAutocomplete, COMMON_COMMANDS, COMMON_FLAGS, filterSuggestions, type TerminalAutocompleteProps, type AutocompleteSuggestion } from './terminal-autocomplete' +export { + TerminalAutocomplete, + useAutocomplete, + COMMON_COMMANDS, + COMMON_FLAGS, + filterSuggestions, + type TerminalAutocompleteProps, + type AutocompleteSuggestion, +} from './terminal-autocomplete' export { TerminalGhosttyTheme, GhosttyThemePicker } from './terminal-ghostty' export { ThemeSwitcher } from './theme-switcher' export { TerminalBadge } from './terminal-badge' +export { TerminalMarker } from './terminal-marker' +export { TerminalLogLine, type TerminalLogLineProps } from './terminal-log-line'