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 with new interactive demos and introduces several new terminal feed primitives (structured log rendering, phase markers, and a controlled filter bar) to support richer log/stream experiences.
Changes:
- Adds structured log support to
TerminalLogvia a newentriesAPI and sharedLogEntrytype. - Introduces new feed primitives/components:
TerminalLogLine,TerminalMarker, andTerminalFilterBar(+filterEntrieshelper). - Updates the playground page layout/sections and adds new demos for the new components.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| components/terminal.tsx | Re-exports new terminal feed components/types via the terminal barrel. |
| components/terminal-marker.tsx | Adds a new phase/section marker row for terminal feeds. |
| components/terminal-log.tsx | Extends TerminalLog to support structured entries rendered with TerminalLogLine. |
| components/terminal-log-line.tsx | Adds a new structured log row primitive with level/timestamp/source columns. |
| components/terminal-filter-bar.tsx | Adds a controlled filter bar UI plus a pure filterEntries() helper. |
| app/playground/page.tsx | Reorganizes playground sections and wires in new demos. |
| app/playground/log-demo.tsx | Adds a structured log demo alongside the existing string log demo. |
| app/playground/filter-demo.tsx | Adds a filter bar demo with sample structured log entries. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| TerminalSearch, | ||
| useTerminalSearch, | ||
| type TerminalSearchProps, | ||
| type UseTerminalSearchOptions, | ||
| type UseTerminalSearchResult, | ||
| } from './terminal-search' | ||
| export { |
There was a problem hiding this comment.
TerminalSearch is exported from ./terminal-search, but there is no components/terminal-search.tsx (or equivalent) in this branch. This will fail the build/module resolution; either add the missing file or remove/adjust these exports to the correct path.
| TerminalSearch, | |
| useTerminalSearch, | |
| type TerminalSearchProps, | |
| type UseTerminalSearchOptions, | |
| type UseTerminalSearchResult, | |
| } from './terminal-search' | |
| export { |
| import { LogDemo, StructuredLogDemo } from './log-demo' | ||
| import { FilterBarDemo } from './filter-demo' | ||
| import { PromptDemo } from './prompt-demo' | ||
| import { SearchDemo } from './search-demo' |
There was a problem hiding this comment.
SearchDemo is imported from ./search-demo, but there is no app/playground/search-demo.tsx in this branch. This will break compilation for the playground page; add the missing file or remove the import/section.
| import { SearchDemo } from './search-demo' |
| {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 Tailwind utility in this repo (and it’s not defined anywhere else), so long unbroken log messages won’t wrap as intended. Consider using an existing utility like break-words/break-all (and/or whitespace-pre-wrap if you want newline preservation) on the message span.
| <span className={`min-w-0 wrap-break-word ${cls.message}`}>{message}</span> | |
| <span className={`min-w-0 break-words ${cls.message}`}>{message}</span> |
| /** | ||
| * 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<NonNullable<TerminalLogLineProps['level']>, string> = { | ||
| debug: 'DBG', | ||
| info: 'INF', | ||
| warn: 'WRN', | ||
| error: 'ERR', | ||
| success: 'OK', | ||
| } |
There was a problem hiding this comment.
The comment says all level labels are exactly 3 characters, but the success label is OK (2 chars). Either pad/rename the label (e.g., 3 chars) or update the comment so it matches the implementation.
| { id: '1', level: 'info', timestamp: '10:23:44', source: 'server', message: 'Application starting up...' }, | ||
| { id: '2', level: 'info', timestamp: '10:23:45', source: 'server', message: 'Listening on :3000' }, | ||
| { id: '3', level: 'debug', timestamp: '10:23:45', source: 'cache', message: 'HIT packages/[email protected]' }, | ||
| { id: '4', level: 'warn', timestamp: '10:23:46', source: 'cache', message: 'MISS @openknots/terminal-ui — fetching from registry' }, | ||
| { id: '5', level: 'info', timestamp: '10:23:47', source: 'build', message: 'Compiling 42 modules...' }, | ||
| { id: '6', level: 'debug', timestamp: '10:23:47', source: 'build', message: 'Resolved tsconfig paths in 4ms' }, | ||
| { id: '7', level: 'success', timestamp: '10:23:48', source: 'build', message: 'Compiled in 1.2s — 0 errors' }, | ||
| { id: '8', level: 'info', timestamp: '10:23:49', source: 'test', message: 'Running 24 unit tests...' }, | ||
| { id: '9', level: 'error', timestamp: '10:23:50', source: 'test', message: 'FAIL src/utils.test.ts — 1 snapshot mismatch' }, | ||
| { id: '10', level: 'info', timestamp: '10:23:50', source: 'test', message: 'Retrying with --updateSnapshot...' }, | ||
| { id: '11', level: 'success', timestamp: '10:23:51', source: 'test', message: '24 / 24 tests passed — coverage 94%' }, | ||
| { id: '12', level: 'info', timestamp: '10:23:52', source: 'deploy', message: 'Uploading artifacts to CDN...' }, | ||
| { id: '13', level: 'warn', timestamp: '10:23:52', source: 'deploy', message: 'Edge cache warm-up taking longer than 5s' }, | ||
| { id: '14', level: 'success', timestamp: '10:23:53', source: 'deploy', message: 'Published to production — https://example.app' }, |
There was a problem hiding this comment.
This file doesn’t appear to be formatted with the repo’s Prettier config (e.g., extra alignment spaces in object literals and long lines that would normally wrap). Running pnpm format (or formatting this file) will prevent noisy diffs and keep formatting consistent.
| { id: '1', level: 'info', timestamp: '10:23:44', source: 'server', message: 'Application starting up...' }, | |
| { id: '2', level: 'info', timestamp: '10:23:45', source: 'server', message: 'Listening on :3000' }, | |
| { id: '3', level: 'debug', timestamp: '10:23:45', source: 'cache', message: 'HIT packages/[email protected]' }, | |
| { id: '4', level: 'warn', timestamp: '10:23:46', source: 'cache', message: 'MISS @openknots/terminal-ui — fetching from registry' }, | |
| { id: '5', level: 'info', timestamp: '10:23:47', source: 'build', message: 'Compiling 42 modules...' }, | |
| { id: '6', level: 'debug', timestamp: '10:23:47', source: 'build', message: 'Resolved tsconfig paths in 4ms' }, | |
| { id: '7', level: 'success', timestamp: '10:23:48', source: 'build', message: 'Compiled in 1.2s — 0 errors' }, | |
| { id: '8', level: 'info', timestamp: '10:23:49', source: 'test', message: 'Running 24 unit tests...' }, | |
| { id: '9', level: 'error', timestamp: '10:23:50', source: 'test', message: 'FAIL src/utils.test.ts — 1 snapshot mismatch' }, | |
| { id: '10', level: 'info', timestamp: '10:23:50', source: 'test', message: 'Retrying with --updateSnapshot...' }, | |
| { id: '11', level: 'success', timestamp: '10:23:51', source: 'test', message: '24 / 24 tests passed — coverage 94%' }, | |
| { id: '12', level: 'info', timestamp: '10:23:52', source: 'deploy', message: 'Uploading artifacts to CDN...' }, | |
| { id: '13', level: 'warn', timestamp: '10:23:52', source: 'deploy', message: 'Edge cache warm-up taking longer than 5s' }, | |
| { id: '14', level: 'success', timestamp: '10:23:53', source: 'deploy', message: 'Published to production — https://example.app' }, | |
| { | |
| id: '1', | |
| level: 'info', | |
| timestamp: '10:23:44', | |
| source: 'server', | |
| message: 'Application starting up...', | |
| }, | |
| { | |
| id: '2', | |
| level: 'info', | |
| timestamp: '10:23:45', | |
| source: 'server', | |
| message: 'Listening on :3000', | |
| }, | |
| { | |
| id: '3', | |
| level: 'debug', | |
| timestamp: '10:23:45', | |
| source: 'cache', | |
| message: 'HIT packages/[email protected]', | |
| }, | |
| { | |
| id: '4', | |
| level: 'warn', | |
| timestamp: '10:23:46', | |
| source: 'cache', | |
| message: 'MISS @openknots/terminal-ui — fetching from registry', | |
| }, | |
| { | |
| id: '5', | |
| level: 'info', | |
| timestamp: '10:23:47', | |
| source: 'build', | |
| message: 'Compiling 42 modules...', | |
| }, | |
| { | |
| id: '6', | |
| level: 'debug', | |
| timestamp: '10:23:47', | |
| source: 'build', | |
| message: 'Resolved tsconfig paths in 4ms', | |
| }, | |
| { | |
| id: '7', | |
| level: 'success', | |
| timestamp: '10:23:48', | |
| source: 'build', | |
| message: 'Compiled in 1.2s — 0 errors', | |
| }, | |
| { | |
| id: '8', | |
| level: 'info', | |
| timestamp: '10:23:49', | |
| source: 'test', | |
| message: 'Running 24 unit tests...', | |
| }, | |
| { | |
| id: '9', | |
| level: 'error', | |
| timestamp: '10:23:50', | |
| source: 'test', | |
| message: 'FAIL src/utils.test.ts — 1 snapshot mismatch', | |
| }, | |
| { | |
| id: '10', | |
| level: 'info', | |
| timestamp: '10:23:50', | |
| source: 'test', | |
| message: 'Retrying with --updateSnapshot...', | |
| }, | |
| { | |
| id: '11', | |
| level: 'success', | |
| timestamp: '10:23:51', | |
| source: 'test', | |
| message: '24 / 24 tests passed — coverage 94%', | |
| }, | |
| { | |
| id: '12', | |
| level: 'info', | |
| timestamp: '10:23:52', | |
| source: 'deploy', | |
| message: 'Uploading artifacts to CDN...', | |
| }, | |
| { | |
| id: '13', | |
| level: 'warn', | |
| timestamp: '10:23:52', | |
| source: 'deploy', | |
| message: 'Edge cache warm-up taking longer than 5s', | |
| }, | |
| { | |
| id: '14', | |
| level: 'success', | |
| timestamp: '10:23:53', | |
| source: 'deploy', | |
| message: 'Published to production — https://example.app', | |
| }, |
This pull request adds several new interactive demos to the playground page, showcasing advanced terminal UI components such as structured logs, log filtering, log line rendering, phase markers, and in-feed search. It also improves the organization and clarity of the playground by updating section titles and descriptions.
New terminal UI component demos:
#10
StructuredLogDemocomponent, demonstrating theTerminalLogin structured mode with level badges, timestamps, and source labels. [1] [2] [3] [4]FilterBarDemocomponent, showcasing theTerminalFilterBarwith interactive level toggles, text search, and source toggles, alongside the usage offilterEntries(). [1] [2] [3]TerminalMarker(phase separators),TerminalLogLine(structured log row primitive), andTerminalSearch(in-feed search with navigation and highlighting). [1] [2]Playground page improvements: