Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions app/playground/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { TerminalApp } from '@/components/terminal-app'
import { Terminal, TerminalCommand, TerminalDiff, TerminalOutput, TerminalSpinner, TerminalBadge, ThemeSwitcher } from '@/components/terminal'
import { TerminalProgress } from '@/components/terminal-progress'
import { TerminalTable } from '@/components/terminal-table'
import { TerminalTabs } from '@/components/terminal-tabs'
import { TerminalSelect } from '@/components/terminal-select'
import { LogDemo } from './log-demo'
import { PromptDemo } from './prompt-demo'
import { TreeDemo } from './tree-demo'
Expand Down Expand Up @@ -175,6 +178,71 @@ export default function PlaygroundPage() {
</TerminalOutput>
</Terminal>
</section>

<section className="flex flex-col gap-2">
<h2 className="text-lg font-semibold font-mono text-[var(--term-fg)]">
TerminalTable
</h2>
<p className="text-sm text-[var(--term-fg-dim)] font-mono">
Data tables with box-drawing characters and alignment options.
</p>
<Terminal title="table-demo.sh">
<TerminalCommand>ls -la /node_modules</TerminalCommand>
<TerminalTable
headers={['Name', 'Version', 'Size', 'Type']}
rows={[
['react', '19.0.0', '142 kB', 'core'],
['next', '15.1.0', '540 kB', 'framework'],
['typescript', '5.7.0', '89 MB', 'language'],
['tailwindcss', '4.0.0', '12 MB', 'utility'],
]}
align={['left', 'left', 'right', 'left']}
striped
/>
</Terminal>
</section>

<section className="flex flex-col gap-2">
<h2 className="text-lg font-semibold font-mono text-[var(--term-fg)]">
TerminalTabs
</h2>
<p className="text-sm text-[var(--term-fg-dim)] font-mono">
Tab bar with keyboard navigation (←→ to navigate, Enter to select).
</p>
<Terminal title="tabs-demo.sh">
<TerminalCommand>open tabs</TerminalCommand>
<TerminalTabs
tabs={[
{ id: '1', label: 'server.ts', icon: '🔥' },
{ id: '2', label: 'client.ts', icon: '⚛️' },
{ id: '3', label: 'config.json', icon: '⚙️' },
{ id: '4', label: 'styles.css', icon: '🎨' },
]}
activeId="1"
variant="blue"
/>
<TerminalOutput type="info">
Use ← → arrow keys to switch tabs
</TerminalOutput>
</Terminal>
</section>

<section className="flex flex-col gap-2">
<h2 className="text-lg font-semibold font-mono text-[var(--term-fg)]">
TerminalSelect
</h2>
<p className="text-sm text-[var(--term-fg-dim)] font-mono">
Dropdown select component styled for terminal aesthetic.
</p>
<Terminal title="select-demo.sh">
<TerminalCommand>select-framework</TerminalCommand>
<TerminalSelect
label="Choose a framework:"
options={['Next.js', 'Nuxt', 'Astro', 'Remix', 'SolidStart']}
variant="blue"
/>
</Terminal>
</section>
</main>
)
}
18 changes: 18 additions & 0 deletions components/terminal-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,24 @@ function uid() {
return `t${++globalId}`
}

/**
* Full terminal application with tabs, split panes, and command palette.
* Provides a complete terminal emulator experience with window management.
*
* @interface Tab
* @property {string} id - Unique identifier for the tab
* @property {string} title - Display title of the tab
* @property {string[]} panes - Array of pane IDs in this tab
*
* @example
* ```tsx
* import { TerminalApp } from '@/components/terminal-app'
*
* function App() {
* return <TerminalApp className="h-screen" />
* }
* ```
*/
function TerminalAppInner({ className }: { className?: string }) {
const { setTheme } = useTheme()
const [tabs, setTabs] = useState<Tab[]>(() => {
Expand Down
2 changes: 1 addition & 1 deletion components/terminal-autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export function TerminalAutocomplete({
className={`px-3 py-2 cursor-pointer transition-colors ${
index === selectedIndex
? 'bg-[var(--term-blue)] bg-opacity-30'
: 'hover:bg-[var(--term-bg-dark)]'
: 'hover:bg-[var(--glass-bg)]'
}`}
onClick={() => onSelect?.(suggestion)}
>
Expand Down
28 changes: 28 additions & 0 deletions components/terminal-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,34 @@ interface TerminalHeaderProps {
onSplit: () => void
}

/**
* Terminal header component with tabs, traffic lights, and theme switcher.
* Provides a tabbed interface for terminal sessions with window controls.
*
* @interface Tab
* @property {string} id - Unique identifier for the tab
* @property {string} title - Display title of the tab
*
* @interface TerminalHeaderProps
* @property {Tab[]} tabs - Array of tab objects to display
* @property {string} activeTab - ID of the currently active tab
* @property {(id: string) => void} onTabChange - Callback when tab is changed
* @property {(id: string) => void} onTabClose - Callback when tab is closed
* @property {() => void} onNewTab - Callback when new tab button is clicked
* @property {() => void} onSplit - Callback when split button is clicked
*
* @example
* ```tsx
* <TerminalHeader
* tabs={[{ id: '1', title: 'bash' }, { id: '2', title: 'zsh' }]}
* activeTab="1"
* onTabChange={(id) => console.log(id)}
* onTabClose={(id) => console.log(id)}
* onNewTab={() => console.log('new')}
* onSplit={() => console.log('split')}
* />
* ```
*/
export function TerminalHeader({
tabs,
activeTab,
Expand Down
24 changes: 24 additions & 0 deletions components/terminal-pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,30 @@ interface TerminalPaneProps {
clearSignal?: number
}

/**
* Interactive terminal pane with command input, history, and filesystem simulation.
* Provides a fully functional terminal emulator with built-in commands.
*
* @interface TerminalPaneProps
* @property {string} id - Unique identifier for this pane
* @property {() => void} onSplit - Callback when split is requested
* @property {() => void} onNewTab - Callback when new tab is requested
* @property {number} tabCount - Number of open tabs (default: 1)
* @property {boolean} isFocused - Whether this pane is focused (default: true)
* @property {() => void} onFocus - Callback when pane receives focus
* @property {number} clearSignal - Signal to clear terminal (increment to trigger)
*
* @example
* ```tsx
* <TerminalPane
* id="pane-1"
* onSplit={() => console.log('split')}
* onNewTab={() => console.log('new tab')}
* tabCount={2}
* isFocused={true}
* />
* ```
*/
export function TerminalPane({
id,
onSplit,
Expand Down
20 changes: 20 additions & 0 deletions components/terminal-status-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,26 @@ interface TerminalStatusBarProps {
cwd?: string
}

/**
* Terminal status bar displaying shell info, current directory, and pane/tab counts.
* Shows at the bottom of the terminal with contextual information.
*
* @interface TerminalStatusBarProps
* @property {number} paneCount - Number of split panes (shows "X panes" when > 1)
* @property {number} tabCount - Number of open tabs (shows "X tabs" when > 1)
* @property {string} shell - Shell name to display (default: 'zsh')
* @property {string} cwd - Current working directory to display (default: '~')
*
* @example
* ```tsx
* <TerminalStatusBar
* paneCount={2}
* tabCount={3}
* shell="zsh"
* cwd="~/projects"
* />
* ```
*/
export function TerminalStatusBar({
paneCount,
tabCount,
Expand Down
26 changes: 26 additions & 0 deletions components/terminal-themes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,32 @@ import {
type ReactNode,
} from 'react'

/**
* Theme system for terminal-ui.
* Provides color schemes that can be applied via CSS data-theme attribute.
*
* @module terminal-themes
*
* @example
* ```tsx
* import { useTheme, THEMES, ThemeProvider } from '@/components/terminal-themes'
*
* function App() {
* return (
* <ThemeProvider>
* <YourApp />
* </ThemeProvider>
* )
* }
*
* function Component() {
* const { theme, setTheme } = useTheme()
* return <button onClick={() => setTheme('dracula')}>Dracula</button>
* }
* ```
*/

/** Available theme definitions with id, display name, and accent color */
export const THEMES = [
{ id: 'default', name: 'Default', accent: '#10b981' },
{ id: 'dracula', name: 'Dracula', accent: '#bd93f9' },
Expand Down