Conversation
…en#7) - New `TerminalMarker` component with typed props and JSDoc - Props: label, timestamp?, variant ('info'|'success'|'warning'|'error'|'neutral') - Theme-aware via CSS custom properties (--term-* variables) - Semantic background tint with color-mix for visual hierarchy (consistent with TerminalBadge) - Responsive: min-w-0 + truncate on timestamp prevents overflow on narrow viewports - Export added to components/terminal.tsx (no breaking changes) - Playground demo added to app/playground/page.tsx
) - New TerminalLogLine component with typed props and JSDoc - Props: message (ReactNode), level, timestamp?, source? - Level badge using 3-char uppercase labels (DBG/INF/WRN/ERR/OK) for consistent monospace alignment - Theme-aware via CSS custom properties; error level colors message text red - Responsive: min-w-0 + wrap-break-word on message prevents overflow - Export added to components/terminal.tsx with re-exported type - Playground demo added with 8 representative log lines
- Add color-mix background tints to level badges (consistent with TerminalBadge) - Fix badge alignment: use w-[calc(3ch+0.5rem)] + justify-center so all 5 levels (DBG/INF/WRN/ERR/OK) render at identical pixel width in monospace layout - Update levelClasses to Tailwind v4 CSS variable shorthand (text-/border-(--term-*)) - Remove 'OK ' trailing-space hack (HTML collapses whitespace); fixed-width badge container is the correct approach
…compat
- New LogEntry type { id?, message, level?, timestamp?, source? }
- New optional entries prop on TerminalLog — takes precedence over lines
- Existing lines?: string[] consumers continue to work with zero changes
- Internally reuses TerminalLogLine for structured rendering (level badges,
timestamps, source labels, color-mix tints)
- maxLines and autoScroll work identically on both paths
- Export LogEntry from components/terminal.tsx
- Add StructuredLogDemo to playground (streaming entries with all 5 levels)
- Use Tailwind v4 CSS variable shorthand in terminal-log.tsx
…n#10) - New TerminalFilterBar controlled component with typed props + JSDoc - Level toggle buttons (DBG/INF/WRN/ERR/OK) with active color-mix tints matching TerminalLogLine badge palette; aria-pressed for a11y - Text search input with inline SVG search icon + clear button (X) - Source toggle buttons — row only rendered when sources prop is non-empty - Clear-all pill shown only when any filter is active - All controls are native <button>/<input> — fully keyboard accessible - Exported pure helper filterEntries(entries, state) for composable use - emptyFilterState() factory for clean initial state - Exports: TerminalFilterBar, filterEntries, emptyFilterState, FilterBarState, TerminalFilterBarProps, LogLevel - FilterBarDemo playground with 14 entries across 5 levels and 4 sources - Entry count indicator: 'N / 14 entries shown'
There was a problem hiding this comment.
Pull request overview
This PR expands the terminal UI playground into a more comprehensive showcase by adding new terminal-feed primitives (grouping, structured log rows, search, filtering, markers) and wiring them into dedicated demos on the playground page.
Changes:
- Add new terminal feed components:
TerminalGroup,TerminalSearch(+useTerminalSearch),TerminalFilterBar(+filterEntries),TerminalMarker,TerminalLogLine, and structured-entry support inTerminalLog. - Update
TerminalLogAPI to supportentries: LogEntry[](structured mode) while keepinglinesas a backward-compatible path. - Add multiple new playground demos and reorganize the playground page sections accordingly.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| components/terminal.tsx | Re-exports new terminal primitives (and updates TerminalLog export typings). |
| components/terminal-log.tsx | Adds structured log entry mode (entries) and updates rendering/scroll behavior. |
| components/terminal-log-line.tsx | Introduces a structured log row primitive with badges/timestamp/source. |
| components/terminal-group.tsx | Adds collapsible grouping for command/output sections with ARIA semantics. |
| components/terminal-search.tsx | Adds TerminalSearch UI + useTerminalSearch hook for in-feed search/navigation. |
| components/terminal-filter-bar.tsx | Adds a controlled filter bar and a pure filtering helper for LogEntry[]. |
| components/terminal-marker.tsx | Adds phase/section marker rows for terminal feeds. |
| app/playground/page.tsx | Integrates and documents new demos/sections in the playground page. |
| app/playground/log-demo.tsx | Adds a structured-log demo alongside the existing string-log demo. |
| app/playground/group-demo.tsx | Adds a demo showcasing controlled/uncontrolled TerminalGroup usage. |
| app/playground/search-demo.tsx | Adds a search demo with highlighting and scroll-into-view behavior. |
| app/playground/filter-demo.tsx | Adds a filter bar demo using TerminalFilterBar + filterEntries. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <div | ||
| ref={containerRef} | ||
| className={`max-h-64 overflow-auto rounded border border-[var(--glass-border)] bg-[var(--term-bg)]/40 p-3 font-mono text-sm ${className}`.trim()} | ||
| className={`max-h-64 overflow-auto rounded border border-(--glass-border) bg-(--term-bg)/40 p-3 font-mono text-xs ${className}`.trim()} |
There was a problem hiding this comment.
TerminalLog now renders with text-xs instead of the previous text-sm, which changes the default appearance for existing consumers even when they still use lines. If this wasn’t intended as a breaking visual change, consider keeping the previous default font size (or making the size configurable) and applying text-xs only where needed (e.g., inside TerminalLogLine).
| className={`max-h-64 overflow-auto rounded border border-(--glass-border) bg-(--term-bg)/40 p-3 font-mono text-xs ${className}`.trim()} | |
| className={`max-h-64 overflow-auto rounded border border-(--glass-border) bg-(--term-bg)/40 p-3 font-mono text-sm ${className}`.trim()} |
| className={`max-h-64 overflow-auto rounded border border-(--glass-border) bg-(--term-bg)/40 p-3 font-mono text-xs ${className}`.trim()} | ||
| role="log" |
There was a problem hiding this comment.
This file introduces Tailwind variable shorthand like border-(--glass-border) / bg-(--term-bg) / text-(--term-fg-dim), while most existing components use the ...[var(--...)] form (e.g., border-[var(--glass-border)], text-[var(--term-fg-dim)]). Mixing both styles makes the styling conventions harder to follow; consider standardizing on one syntax across the component library.
| useTerminalSearch, | ||
| type LogEntry, | ||
| } from '@/components/terminal' | ||
| import { TerminalLog } from '@/components/terminal-log' |
There was a problem hiding this comment.
TerminalLog is imported from @/components/terminal-log but never used. This can fail linting and should be removed (or use the component if intended).
| import { TerminalLog } from '@/components/terminal-log' |
| export { TerminalStackTrace, type TerminalStackTraceProps } from './terminal-stack-trace' | ||
| export { TerminalJsonLine, type TerminalJsonLineProps } from './terminal-json-line' |
There was a problem hiding this comment.
TerminalStackTrace / TerminalJsonLine are exported from ./terminal-stack-trace and ./terminal-json-line, but those modules don’t exist in the repo (so this will fail at build/tsc time). Add the missing component files (and ensure they’re included in the PR) or remove these exports.
| export { TerminalStackTrace, type TerminalStackTraceProps } from './terminal-stack-trace' | |
| export { TerminalJsonLine, type TerminalJsonLineProps } from './terminal-json-line' |
| import { LogDemo } from './log-demo' | ||
| import { LogDemo, StructuredLogDemo } from './log-demo' | ||
| import { FilterBarDemo } from './filter-demo' | ||
| import { TerminalJsonLine } from '@/components/terminal' |
There was a problem hiding this comment.
TerminalJsonLine is imported/used from @/components/terminal, but the underlying ./terminal-json-line module is not present in components/ (so this import/export chain will fail). Either include the missing component implementation in this PR or remove this demo section until it exists.
| import { TerminalJsonLine } from '@/components/terminal' |
| import { SearchDemo } from './search-demo' | ||
| import { TreeDemo } from './tree-demo' | ||
| import { TreeKeyboardDemo } from './tree-keyboard-demo' | ||
| import { StackTraceDemo } from './stack-trace-demo' |
There was a problem hiding this comment.
StackTraceDemo is imported from ./stack-trace-demo, but there is no app/playground/stack-trace-demo.tsx in the repo. This will break the playground page build; add the missing file or remove the import/section.
| import { StackTraceDemo } from './stack-trace-demo' |
| // Clamp currentIndex whenever matchIndices changes. | ||
| const safeCurrentIndex = | ||
| matchIndices.length === 0 ? -1 : Math.min(currentIndex, matchIndices.length - 1) | ||
|
|
||
| const setQuery = useCallback((q: string) => { | ||
| setQueryRaw(q) | ||
| setCurrentIndex(0) | ||
| }, []) | ||
|
|
||
| const next = useCallback(() => { | ||
| if (matchIndices.length === 0) return | ||
| setCurrentIndex((prev) => (prev + 1) % matchIndices.length) | ||
| }, [matchIndices.length]) | ||
|
|
||
| const prev = useCallback(() => { | ||
| if (matchIndices.length === 0) return | ||
| setCurrentIndex((prev) => (prev - 1 + matchIndices.length) % matchIndices.length) | ||
| }, [matchIndices.length]) |
There was a problem hiding this comment.
In useTerminalSearch, safeCurrentIndex is derived but the currentIndex state is never clamped when matchIndices shrinks (e.g., when items changes). Because next/prev use the raw state value, navigation can get stuck on the wrong index when currentIndex is out of range. Consider clamping currentIndex in an effect when matchIndices changes, or compute the next/prev index from safeCurrentIndex instead of the stale state.
| {source && <span className="shrink-0 text-(--term-fg-dim)">{source}</span>} | ||
|
|
||
| {/* Message */} | ||
| <span className={`min-w-0 wrap-break-word ${cls.message}`}>{message}</span> |
There was a problem hiding this comment.
wrap-break-word isn’t a standard Tailwind utility, so the message text likely won’t break long tokens and can overflow the container. Replace it with a valid wrapping strategy (e.g., break-words/break-all, optionally combined with whitespace-pre-wrap depending on desired formatting).
| <span className={`min-w-0 wrap-break-word ${cls.message}`}>{message}</span> | |
| <span className={`min-w-0 break-words ${cls.message}`}>{message}</span> |
#12
This pull request adds several new interactive demos to the playground for the terminal UI components, expanding coverage for structured logs, filtering, grouping, searching, and stack traces. It also improves the organization and clarity of the playground page by updating section headers and descriptions, and by integrating the new demos into the main showcase.
New playground demos:
FilterBarDemoto demonstrate terminal log filtering by source, level, and text, using theTerminalFilterBarand simulated log entries. (app/playground/filter-demo.tsx,app/playground/page.tsx) [1] [2]StructuredLogDemoto showcase structured log streaming with badges, timestamps, and sources using theTerminalLogcomponent in structured mode. (app/playground/log-demo.tsx,app/playground/page.tsx) [1] [2] [3]GroupDemoto demonstrate collapsible terminal output sections viaTerminalGroup, including controlled and uncontrolled open/close states and variant accents. (app/playground/group-demo.tsx,app/playground/page.tsx) [1] [2]SearchDemo) and stack traces (StackTraceDemo) into the playground page. (app/playground/page.tsx)Playground page improvements:
app/playground/page.tsx) [1] [2] [3] [4] [5] [6] [7]These changes make the playground a more comprehensive and interactive showcase for terminal UI features, helping developers understand and test each component in isolation.