Add Chinese documentation for custom skills development and reference guide

- Created a new document for custom skills development (`custom.md`) detailing the structure, creation, implementation, and best practices for developing custom CCW skills.
- Added an index document (`index.md`) summarizing all built-in skills, their categories, and usage examples.
- Introduced a reference guide (`reference.md`) providing a quick reference for all 33 built-in CCW skills, including triggers and purposes.
This commit is contained in:
catlog22
2026-03-01 13:08:12 +08:00
parent 2fb93d20e0
commit 8ceae6d6fd
78 changed files with 12352 additions and 3638 deletions

View File

@@ -0,0 +1,326 @@
/**
* Component Gallery Demo
* Interactive showcase of all UI components
*/
import React, { useState } from 'react'
export default function ComponentGallery() {
const [selectedCategory, setSelectedCategory] = useState('all')
const [buttonVariant, setButtonVariant] = useState('default')
const [switchState, setSwitchState] = useState(false)
const [checkboxState, setCheckboxState] = useState(false)
const [selectedTab, setSelectedTab] = useState('variants')
const categories = [
{ id: 'all', label: 'All Components' },
{ id: 'buttons', label: 'Buttons' },
{ id: 'forms', label: 'Forms' },
{ id: 'feedback', label: 'Feedback' },
{ id: 'navigation', label: 'Navigation' },
{ id: 'overlays', label: 'Overlays' },
]
const buttonVariants = ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link']
return (
<div className="p-6 bg-background space-y-8">
{/* Header */}
<div>
<h1 className="text-2xl font-bold">UI Component Library</h1>
<p className="text-muted-foreground">Interactive showcase of all available UI components</p>
</div>
{/* Category Filter */}
<div className="flex flex-wrap gap-2">
{categories.map((cat) => (
<button
key={cat.id}
onClick={() => setSelectedCategory(cat.id)}
className={`px-4 py-2 rounded-md text-sm transition-colors ${
selectedCategory === cat.id
? 'bg-primary text-primary-foreground'
: 'border hover:bg-accent'
}`}
>
{cat.label}
</button>
))}
</div>
{/* Buttons Section */}
{(selectedCategory === 'all' || selectedCategory === 'buttons') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold">Buttons</h2>
<div className="space-y-6">
{/* Variant Selector */}
<div className="space-y-3">
<label className="text-sm font-medium">Variant</label>
<div className="flex flex-wrap gap-2">
{buttonVariants.map((variant) => (
<button
key={variant}
onClick={() => setButtonVariant(variant)}
className={`px-4 py-2 rounded-md text-sm capitalize transition-colors ${
buttonVariant === variant
? 'bg-primary text-primary-foreground ring-2 ring-ring'
: 'border hover:bg-accent'
}`}
>
{variant}
</button>
))}
</div>
</div>
{/* Button Sizes */}
<div className="space-y-3">
<label className="text-sm font-medium">Sizes</label>
<div className="flex items-center gap-3 flex-wrap">
<button className={`h-8 rounded-md px-3 text-sm ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
Small
</button>
<button className={`h-10 px-4 py-2 rounded-md text-sm ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
Default
</button>
<button className={`h-11 rounded-md px-8 text-sm ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
Large
</button>
<button className={`h-10 w-10 rounded-md flex items-center justify-center ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
</button>
</div>
</div>
{/* All Button Variants */}
<div className="space-y-3">
<label className="text-sm font-medium">All Variants</label>
<div className="flex flex-wrap gap-3 p-4 border rounded-lg bg-muted/20">
<button className="px-4 py-2 rounded-md text-sm bg-primary text-primary-foreground hover:opacity-90">Default</button>
<button className="px-4 py-2 rounded-md text-sm bg-destructive text-destructive-foreground hover:opacity-90">Destructive</button>
<button className="px-4 py-2 rounded-md text-sm border bg-background hover:bg-accent">Outline</button>
<button className="px-4 py-2 rounded-md text-sm bg-secondary text-secondary-foreground hover:opacity-80">Secondary</button>
<button className="px-4 py-2 rounded-md text-sm hover:bg-accent">Ghost</button>
<button className="px-4 py-2 rounded-md text-sm text-primary underline-offset-4 hover:underline">Link</button>
<button className="px-4 py-2 rounded-md text-sm bg-gradient-to-r from-blue-500 to-purple-500 text-white hover:opacity-90">Gradient</button>
</div>
</div>
</div>
</section>
)}
{/* Forms Section */}
{(selectedCategory === 'all' || selectedCategory === 'forms') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold">Form Components</h2>
<div className="grid md:grid-cols-2 gap-6">
{/* Input */}
<div className="space-y-3">
<label className="text-sm font-medium">Input</label>
<input
type="text"
placeholder="Enter text..."
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
<input
type="text"
placeholder="Error state"
className="flex h-10 w-full rounded-md border border-destructive bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-destructive"
/>
</div>
{/* Textarea */}
<div className="space-y-3">
<label className="text-sm font-medium">Textarea</label>
<textarea
placeholder="Enter multi-line text..."
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
</div>
{/* Checkbox */}
<div className="space-y-3">
<label className="text-sm font-medium">Checkbox</label>
<div className="space-y-2">
<label className="flex items-center gap-2 text-sm cursor-pointer">
<input type="checkbox" className="h-4 w-4 rounded border border-primary" checked={checkboxState} onChange={(e) => setCheckboxState(e.target.checked)} />
<span>Accept terms and conditions</span>
</label>
<label className="flex items-center gap-2 text-sm cursor-pointer opacity-50">
<input type="checkbox" className="h-4 w-4 rounded border border-primary" />
<span>Subscribe to newsletter</span>
</label>
</div>
</div>
{/* Switch */}
<div className="space-y-3">
<label className="text-sm font-medium">Switch</label>
<div className="space-y-3">
<label className="flex items-center gap-3 cursor-pointer">
<div className="relative">
<input type="checkbox" className="sr-only peer" checked={switchState} onChange={(e) => setSwitchState(e.target.checked)} />
<div className="w-9 h-5 bg-input rounded-full peer peer-focus:ring-2 peer-focus:ring-ring peer-checked:bg-primary after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-background after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:after:translate-x-full" />
</div>
<span className="text-sm">Enable notifications {switchState ? '(on)' : '(off)'}</span>
</label>
</div>
</div>
{/* Select */}
<div className="space-y-3">
<label className="text-sm font-medium">Select</label>
<select className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring">
<option value="">Choose an option</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
</div>
{/* Form Actions */}
<div className="space-y-3">
<label className="text-sm font-medium">Form Actions</label>
<div className="flex gap-2">
<button className="px-4 py-2 rounded-md text-sm bg-primary text-primary-foreground hover:opacity-90">Submit</button>
<button className="px-4 py-2 rounded-md text-sm border hover:bg-accent">Cancel</button>
</div>
</div>
</div>
</section>
)}
{/* Feedback Section */}
{(selectedCategory === 'all' || selectedCategory === 'feedback') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold">Feedback Components</h2>
{/* Badges */}
<div className="space-y-3">
<label className="text-sm font-medium">Badges</label>
<div className="flex flex-wrap gap-2">
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-primary text-primary-foreground">Default</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-secondary text-secondary-foreground">Secondary</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-destructive text-destructive-foreground">Destructive</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-success text-white">Success</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-warning text-white">Warning</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-info text-white">Info</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold text-foreground">Outline</span>
</div>
</div>
{/* Progress */}
<div className="space-y-3">
<label className="text-sm font-medium">Progress Bars</label>
<div className="space-y-3 max-w-md">
<div>
<div className="flex justify-between text-xs mb-1">
<span>Processing...</span>
<span>65%</span>
</div>
<div className="h-2 bg-muted rounded-full overflow-hidden">
<div className="h-full bg-primary rounded-full transition-all" style={{ width: '65%' }}/>
</div>
</div>
<div>
<div className="flex justify-between text-xs mb-1">
<span>Uploading...</span>
<span>30%</span>
</div>
<div className="h-2 bg-muted rounded-full overflow-hidden">
<div className="h-full bg-blue-500 rounded-full transition-all" style={{ width: '30%' }}/>
</div>
</div>
</div>
</div>
{/* Alerts */}
<div className="space-y-3">
<label className="text-sm font-medium">Alerts</label>
<div className="space-y-3">
<div className="flex items-start gap-3 p-4 border rounded-lg bg-destructive/10 border-destructive/20 text-destructive">
<span className="text-lg"></span>
<div className="flex-1">
<div className="font-medium text-sm">Error occurred</div>
<div className="text-xs mt-1 opacity-80">Something went wrong. Please try again.</div>
</div>
</div>
<div className="flex items-start gap-3 p-4 border rounded-lg bg-success/10 border-success/20 text-success">
<span className="text-lg"></span>
<div className="flex-1">
<div className="font-medium text-sm">Success!</div>
<div className="text-xs mt-1 opacity-80">Your changes have been saved.</div>
</div>
</div>
</div>
</div>
</section>
)}
{/* Navigation Section */}
{(selectedCategory === 'all' || selectedCategory === 'navigation') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold">Navigation Components</h2>
{/* Tabs */}
<div className="space-y-3">
<label className="text-sm font-medium">Tabs</label>
<div className="border-b">
<div className="flex gap-4">
{['Overview', 'Documentation', 'API Reference', 'Examples'].map((tab) => (
<button
key={tab}
onClick={() => setSelectedTab(tab.toLowerCase().replace(' ', '-'))}
className={`pb-3 px-1 text-sm border-b-2 transition-colors ${
selectedTab === tab.toLowerCase().replace(' ', '-')
? 'border-primary text-primary'
: 'border-transparent text-muted-foreground hover:text-foreground'
}`}
>
{tab}
</button>
))}
</div>
</div>
</div>
{/* Breadcrumb */}
<div className="space-y-3">
<label className="text-sm font-medium">Breadcrumb</label>
<nav className="flex items-center gap-2 text-sm text-muted-foreground">
<a href="#" className="hover:text-foreground">Home</a>
<span>/</span>
<a href="#" className="hover:text-foreground">Components</a>
<span>/</span>
<span className="text-foreground">Library</span>
</nav>
</div>
</section>
)}
{/* Overlays Section */}
{(selectedCategory === 'all' || selectedCategory === 'overlays') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold">Overlay Components</h2>
<div className="grid md:grid-cols-3 gap-4 text-sm">
<div className="p-4 border rounded-lg">
<h3 className="font-medium mb-2">Dialog</h3>
<p className="text-muted-foreground text-xs">Modal dialogs for focused user interactions.</p>
<button className="mt-3 px-3 py-1.5 text-xs bg-primary text-primary-foreground rounded">Open Dialog</button>
</div>
<div className="p-4 border rounded-lg">
<h3 className="font-medium mb-2">Drawer</h3>
<p className="text-muted-foreground text-xs">Side panels that slide in from screen edges.</p>
<button className="mt-3 px-3 py-1.5 text-xs border rounded hover:bg-accent">Open Drawer</button>
</div>
<div className="p-4 border rounded-lg">
<h3 className="font-medium mb-2">Dropdown Menu</h3>
<p className="text-muted-foreground text-xs">Context menus and action lists.</p>
<button className="mt-3 px-3 py-1.5 text-xs border rounded hover:bg-accent"> Open Menu</button>
</div>
</div>
</section>
)}
</div>
)
}

View File

@@ -0,0 +1,326 @@
/**
* 组件库展示演示 (中文版)
* 所有 UI 组件的交互式展示
*/
import React, { useState } from 'react'
export default function ComponentGalleryZh() {
const [selectedCategory, setSelectedCategory] = useState('all')
const [buttonVariant, setButtonVariant] = useState('default')
const [switchState, setSwitchState] = useState(false)
const [checkboxState, setCheckboxState] = useState(false)
const [selectedTab, setSelectedTab] = useState('variants')
const categories = [
{ id: 'all', label: '全部组件' },
{ id: 'buttons', label: '按钮' },
{ id: 'forms', label: '表单' },
{ id: 'feedback', label: '反馈' },
{ id: 'navigation', label: '导航' },
{ id: 'overlays', label: '叠加层' },
]
const buttonVariants = ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link']
return (
<div className="p-6 bg-background space-y-8">
{/* 标题 */}
<div>
<h1 className="text-2xl font-bold">UI </h1>
<p className="text-muted-foreground"> UI </p>
</div>
{/* 分类筛选 */}
<div className="flex flex-wrap gap-2">
{categories.map((cat) => (
<button
key={cat.id}
onClick={() => setSelectedCategory(cat.id)}
className={`px-4 py-2 rounded-md text-sm transition-colors ${
selectedCategory === cat.id
? 'bg-primary text-primary-foreground'
: 'border hover:bg-accent'
}`}
>
{cat.label}
</button>
))}
</div>
{/* 按钮部分 */}
{(selectedCategory === 'all' || selectedCategory === 'buttons') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold"></h2>
<div className="space-y-6">
{/* 变体选择器 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<div className="flex flex-wrap gap-2">
{buttonVariants.map((variant) => (
<button
key={variant}
onClick={() => setButtonVariant(variant)}
className={`px-4 py-2 rounded-md text-sm capitalize transition-colors ${
buttonVariant === variant
? 'bg-primary text-primary-foreground ring-2 ring-ring'
: 'border hover:bg-accent'
}`}
>
{variant}
</button>
))}
</div>
</div>
{/* 按钮尺寸 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<div className="flex items-center gap-3 flex-wrap">
<button className={`h-8 rounded-md px-3 text-sm ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
</button>
<button className={`h-10 px-4 py-2 rounded-md text-sm ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
</button>
<button className={`h-11 rounded-md px-8 text-sm ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
</button>
<button className={`h-10 w-10 rounded-md flex items-center justify-center ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
</button>
</div>
</div>
{/* 所有按钮变体 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<div className="flex flex-wrap gap-3 p-4 border rounded-lg bg-muted/20">
<button className="px-4 py-2 rounded-md text-sm bg-primary text-primary-foreground hover:opacity-90"></button>
<button className="px-4 py-2 rounded-md text-sm bg-destructive text-destructive-foreground hover:opacity-90"></button>
<button className="px-4 py-2 rounded-md text-sm border bg-background hover:bg-accent"></button>
<button className="px-4 py-2 rounded-md text-sm bg-secondary text-secondary-foreground hover:opacity-80"></button>
<button className="px-4 py-2 rounded-md text-sm hover:bg-accent"></button>
<button className="px-4 py-2 rounded-md text-sm text-primary underline-offset-4 hover:underline"></button>
<button className="px-4 py-2 rounded-md text-sm bg-gradient-to-r from-blue-500 to-purple-500 text-white hover:opacity-90"></button>
</div>
</div>
</div>
</section>
)}
{/* 表单部分 */}
{(selectedCategory === 'all' || selectedCategory === 'forms') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold"></h2>
<div className="grid md:grid-cols-2 gap-6">
{/* 输入框 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<input
type="text"
placeholder="输入文本..."
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
<input
type="text"
placeholder="错误状态"
className="flex h-10 w-full rounded-md border border-destructive bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-destructive"
/>
</div>
{/* 文本域 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<textarea
placeholder="输入多行文本..."
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
</div>
{/* 复选框 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<div className="space-y-2">
<label className="flex items-center gap-2 text-sm cursor-pointer">
<input type="checkbox" className="h-4 w-4 rounded border border-primary" checked={checkboxState} onChange={(e) => setCheckboxState(e.target.checked)} />
<span></span>
</label>
<label className="flex items-center gap-2 text-sm cursor-pointer opacity-50">
<input type="checkbox" className="h-4 w-4 rounded border border-primary" />
<span></span>
</label>
</div>
</div>
{/* 开关 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<div className="space-y-3">
<label className="flex items-center gap-3 cursor-pointer">
<div className="relative">
<input type="checkbox" className="sr-only peer" checked={switchState} onChange={(e) => setSwitchState(e.target.checked)} />
<div className="w-9 h-5 bg-input rounded-full peer peer-focus:ring-2 peer-focus:ring-ring peer-checked:bg-primary after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-background after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:after:translate-x-full" />
</div>
<span className="text-sm"> {switchState ? '(开)' : '(关)'}</span>
</label>
</div>
</div>
{/* 选择器 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<select className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring">
<option value=""></option>
<option value="1"> 1</option>
<option value="2"> 2</option>
<option value="3"> 3</option>
</select>
</div>
{/* 表单操作 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<div className="flex gap-2">
<button className="px-4 py-2 rounded-md text-sm bg-primary text-primary-foreground hover:opacity-90"></button>
<button className="px-4 py-2 rounded-md text-sm border hover:bg-accent"></button>
</div>
</div>
</div>
</section>
)}
{/* 反馈部分 */}
{(selectedCategory === 'all' || selectedCategory === 'feedback') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold"></h2>
{/* 徽标 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<div className="flex flex-wrap gap-2">
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-primary text-primary-foreground"></span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-secondary text-secondary-foreground"></span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-destructive text-destructive-foreground"></span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-success text-white"></span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-warning text-white"></span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-info text-white"></span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold text-foreground"></span>
</div>
</div>
{/* 进度条 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<div className="space-y-3 max-w-md">
<div>
<div className="flex justify-between text-xs mb-1">
<span>...</span>
<span>65%</span>
</div>
<div className="h-2 bg-muted rounded-full overflow-hidden">
<div className="h-full bg-primary rounded-full transition-all" style={{ width: '65%' }}/>
</div>
</div>
<div>
<div className="flex justify-between text-xs mb-1">
<span>...</span>
<span>30%</span>
</div>
<div className="h-2 bg-muted rounded-full overflow-hidden">
<div className="h-full bg-blue-500 rounded-full transition-all" style={{ width: '30%' }}/>
</div>
</div>
</div>
</div>
{/* 提示 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<div className="space-y-3">
<div className="flex items-start gap-3 p-4 border rounded-lg bg-destructive/10 border-destructive/20 text-destructive">
<span className="text-lg"></span>
<div className="flex-1">
<div className="font-medium text-sm"></div>
<div className="text-xs mt-1 opacity-80"></div>
</div>
</div>
<div className="flex items-start gap-3 p-4 border rounded-lg bg-success/10 border-success/20 text-success">
<span className="text-lg"></span>
<div className="flex-1">
<div className="font-medium text-sm"></div>
<div className="text-xs mt-1 opacity-80"></div>
</div>
</div>
</div>
</div>
</section>
)}
{/* 导航部分 */}
{(selectedCategory === 'all' || selectedCategory === 'navigation') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold"></h2>
{/* 标签页 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<div className="border-b">
<div className="flex gap-4">
{['概览', '文档', 'API 参考', '示例'].map((tab) => (
<button
key={tab}
onClick={() => setSelectedTab(tab.toLowerCase().replace(' ', '-'))}
className={`pb-3 px-1 text-sm border-b-2 transition-colors ${
selectedTab === tab.toLowerCase().replace(' ', '-')
? 'border-primary text-primary'
: 'border-transparent text-muted-foreground hover:text-foreground'
}`}
>
{tab}
</button>
))}
</div>
</div>
</div>
{/* 面包屑 */}
<div className="space-y-3">
<label className="text-sm font-medium"></label>
<nav className="flex items-center gap-2 text-sm text-muted-foreground">
<a href="#" className="hover:text-foreground"></a>
<span>/</span>
<a href="#" className="hover:text-foreground"></a>
<span>/</span>
<span className="text-foreground"></span>
</nav>
</div>
</section>
)}
{/* 叠加层部分 */}
{(selectedCategory === 'all' || selectedCategory === 'overlays') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold"></h2>
<div className="grid md:grid-cols-3 gap-4 text-sm">
<div className="p-4 border rounded-lg">
<h3 className="font-medium mb-2"></h3>
<p className="text-muted-foreground text-xs"></p>
<button className="mt-3 px-3 py-1.5 text-xs bg-primary text-primary-foreground rounded"></button>
</div>
<div className="p-4 border rounded-lg">
<h3 className="font-medium mb-2"></h3>
<p className="text-muted-foreground text-xs"></p>
<button className="mt-3 px-3 py-1.5 text-xs border rounded hover:bg-accent"></button>
</div>
<div className="p-4 border rounded-lg">
<h3 className="font-medium mb-2"></h3>
<p className="text-muted-foreground text-xs"></p>
<button className="mt-3 px-3 py-1.5 text-xs border rounded hover:bg-accent"> </button>
</div>
</div>
</section>
)}
</div>
)
}

View File

@@ -0,0 +1,137 @@
/**
* Dashboard Overview Demo
* Shows the main dashboard layout with widgets
*/
import React from 'react'
export default function DashboardOverview() {
return (
<div className="space-y-6 p-6 bg-background min-h-[600px]">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold">Dashboard</h1>
<p className="text-sm text-muted-foreground">
Project overview and activity monitoring
</p>
</div>
<button className="px-3 py-1.5 text-sm border rounded-md hover:bg-accent">
Refresh
</button>
</div>
{/* Workflow Stats Widget */}
<div className="border rounded-lg overflow-hidden">
<div className="p-4 border-b bg-muted/30">
<h2 className="font-semibold">Project Overview & Statistics</h2>
</div>
<div className="p-4">
<div className="grid grid-cols-3 gap-4">
<div className="space-y-3">
<div className="text-xs font-medium text-muted-foreground">Statistics</div>
<div className="grid grid-cols-2 gap-2">
{[
{ label: 'Active Sessions', value: '12', color: 'text-blue-500' },
{ label: 'Total Tasks', value: '48', color: 'text-green-500' },
{ label: 'Completed', value: '35', color: 'text-emerald-500' },
{ label: 'Pending', value: '8', color: 'text-amber-500' },
].map((stat, i) => (
<div key={i} className="p-2 bg-muted/50 rounded">
<div className={`text-lg font-bold ${stat.color}`}>{stat.value}</div>
<div className="text-xs text-muted-foreground truncate">{stat.label}</div>
</div>
))}
</div>
</div>
<div className="space-y-3">
<div className="text-xs font-medium text-muted-foreground">Workflow Status</div>
<div className="flex items-center justify-center h-24">
<div className="relative w-20 h-20">
<svg className="w-full h-full -rotate-90" viewBox="0 0 36 36">
<circle cx="18" cy="18" r="15" fill="none" stroke="currentColor" strokeWidth="3" className="text-muted opacity-20"/>
<circle cx="18" cy="18" r="15" fill="none" stroke="currentColor" strokeWidth="3" className="text-blue-500" strokeDasharray="70 100"/>
</svg>
<div className="absolute inset-0 flex items-center justify-center text-xs font-bold">70%</div>
</div>
</div>
<div className="text-xs text-center space-y-1">
<div className="flex items-center justify-center gap-1">
<div className="w-2 h-2 rounded-full bg-blue-500"/>
<span>Completed: 70%</span>
</div>
</div>
</div>
<div className="space-y-3">
<div className="text-xs font-medium text-muted-foreground">Recent Session</div>
<div className="p-3 bg-accent/20 rounded border">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium">Feature: Auth Flow</span>
<span className="text-xs px-2 py-0.5 rounded-full bg-green-500/20 text-green-600">Running</span>
</div>
<div className="space-y-1.5">
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded bg-green-500"/>
<span>Implement login</span>
</div>
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded bg-amber-500"/>
<span>Add OAuth</span>
</div>
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded bg-muted"/>
<span className="text-muted-foreground">Test flow</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Recent Sessions Widget */}
<div className="border rounded-lg overflow-hidden">
<div className="border-b bg-muted/30">
<div className="flex gap-1 p-2">
{['All Tasks', 'Workflow', 'Lite Tasks'].map((tab, i) => (
<button
key={tab}
className={`px-3 py-1.5 text-xs rounded-md transition-colors ${
i === 0 ? 'bg-background text-foreground' : 'text-muted-foreground hover:bg-foreground/5'
}`}
>
{tab}
</button>
))}
</div>
</div>
<div className="p-4">
<div className="grid grid-cols-3 gap-3">
{[
{ name: 'Refactor UI Components', status: 'In Progress', progress: 65 },
{ name: 'Fix Login Bug', status: 'Pending', progress: 0 },
{ name: 'Add Dark Mode', status: 'Completed', progress: 100 },
].map((task, i) => (
<div key={i} className="p-3 bg-muted/30 rounded border cursor-pointer hover:border-primary/30">
<div className="flex items-center justify-between mb-2">
<span className="text-xs font-medium line-clamp-1">{task.name}</span>
<span className={`text-xs px-1.5 py-0.5 rounded ${
task.status === 'Completed' ? 'bg-green-500/20 text-green-600' :
task.status === 'In Progress' ? 'bg-blue-500/20 text-blue-600' :
'bg-gray-500/20 text-gray-600'
}`}>{task.status}</span>
</div>
{task.progress > 0 && task.progress < 100 && (
<div className="w-full h-1.5 bg-muted rounded-full overflow-hidden">
<div className="h-full bg-blue-500 rounded-full" style={{ width: `${task.progress}%` }}/>
</div>
)}
</div>
))}
</div>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,82 @@
/**
* Floating Panels Demo
* Mutually exclusive overlay panels
*/
import React, { useState } from 'react'
export default function FloatingPanelsDemo() {
const [activePanel, setActivePanel] = useState<string | null>(null)
const panels = [
{ id: 'issues', title: 'Issues + Queue', side: 'left', width: 400 },
{ id: 'queue', title: 'Queue', side: 'right', width: 320 },
{ id: 'inspector', title: 'Inspector', side: 'right', width: 280 },
{ id: 'execution', title: 'Execution Monitor', side: 'right', width: 300 },
{ id: 'scheduler', title: 'Scheduler', side: 'right', width: 260 },
]
return (
<div className="relative h-[500px] p-6 bg-background border rounded-lg">
<div className="flex items-center justify-between mb-4">
<h3 className="text-sm font-semibold">Floating Panels</h3>
<div className="flex gap-2 flex-wrap">
{panels.map((panel) => (
<button
key={panel.id}
onClick={() => setActivePanel(activePanel === panel.id ? null : panel.id)}
className={`px-3 py-1.5 text-xs rounded transition-colors ${
activePanel === panel.id
? 'bg-primary text-primary-foreground'
: 'border hover:bg-accent'
}`}
>
{panel.title}
</button>
))}
</div>
</div>
<div className="h-[380px] bg-muted/20 border rounded flex items-center justify-center">
<p className="text-sm text-muted-foreground">
{activePanel ? `"${panels.find((p) => p.id === activePanel)?.title}" panel is open` : 'Click a button to open a floating panel'}
</p>
</div>
{/* Floating Panel Overlay */}
{activePanel && (
<div
className={`absolute top-16 border rounded-lg shadow-lg bg-background ${
panels.find((p) => p.id === activePanel)?.side === 'left' ? 'left-6' : 'right-6'
}`}
style={{ width: panels.find((p) => p.id === activePanel)?.width }}
>
<div className="flex items-center justify-between px-3 py-2 border-b">
<span className="text-sm font-medium">{panels.find((p) => p.id === activePanel)?.title}</span>
<button
onClick={() => setActivePanel(null)}
className="text-xs hover:bg-accent px-2 py-1 rounded"
>
</button>
</div>
<div className="p-4 text-sm text-muted-foreground">
<div className="space-y-2">
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-blue-500"/>
<span>Item 1</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"/>
<span>Item 2</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-amber-500"/>
<span>Item 3</span>
</div>
</div>
</div>
</div>
)}
</div>
)
}

View File

@@ -0,0 +1,54 @@
/**
* Mini Stat Cards Demo
* Individual statistics cards with sparkline trends
*/
import React from 'react'
export default function MiniStatCards() {
const stats = [
{ label: 'Active Sessions', value: 12, trend: [8, 10, 9, 11, 10, 12, 12], color: 'blue' },
{ label: 'Total Tasks', value: 48, trend: [40, 42, 45, 44, 46, 47, 48], color: 'green' },
{ label: 'Completed', value: 35, trend: [25, 28, 30, 32, 33, 34, 35], color: 'emerald' },
{ label: 'Pending', value: 8, trend: [12, 10, 11, 9, 8, 7, 8], color: 'amber' },
{ label: 'Failed', value: 5, trend: [3, 4, 3, 5, 4, 5, 5], color: 'red' },
{ label: 'Today Activity', value: 23, trend: [5, 10, 15, 18, 20, 22, 23], color: 'purple' },
]
const colorMap = {
blue: 'text-blue-500 bg-blue-500/10',
green: 'text-green-500 bg-green-500/10',
emerald: 'text-emerald-500 bg-emerald-500/10',
amber: 'text-amber-500 bg-amber-500/10',
red: 'text-red-500 bg-red-500/10',
purple: 'text-purple-500 bg-purple-500/10',
}
return (
<div className="p-6 bg-background">
<h3 className="text-sm font-semibold mb-4">Statistics with Sparklines</h3>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
{stats.map((stat, i) => (
<div key={i} className="p-4 border rounded-lg bg-card">
<div className="flex items-center justify-between mb-2">
<span className="text-xs text-muted-foreground">{stat.label}</span>
<div className={`w-2 h-2 rounded-full ${colorMap[stat.color].split(' ')[1]}`}/>
</div>
<div className={`text-2xl font-bold ${colorMap[stat.color].split(' ')[0]}`}>{stat.value}</div>
<div className="mt-2 h-8 flex items-end gap-0.5">
{stat.trend.map((v, j) => (
<div
key={j}
className="flex-1 rounded-t"
style={{
height: `${(v / Math.max(...stat.trend)) * 100}%`,
backgroundColor: v === stat.value ? 'currentColor' : 'rgba(59, 130, 246, 0.3)',
}}
/>
))}
</div>
</div>
))}
</div>
</div>
)
}

View File

@@ -0,0 +1,66 @@
/**
* Project Info Banner Demo
* Expandable project information with tech stack
*/
import React, { useState } from 'react'
export default function ProjectInfoBanner() {
const [expanded, setExpanded] = useState(false)
return (
<div className="p-6 bg-background">
<h3 className="text-sm font-semibold mb-4">Project Info Banner</h3>
<div className="border rounded-lg overflow-hidden">
{/* Banner Header */}
<div className="p-4 bg-muted/30 flex items-center justify-between">
<div>
<h4 className="font-semibold">My Awesome Project</h4>
<p className="text-sm text-muted-foreground">A modern web application built with React</p>
</div>
<button
onClick={() => setExpanded(!expanded)}
className="p-2 rounded-md hover:bg-accent"
>
<svg className={`w-5 h-5 transition-transform ${expanded ? 'rotate-180' : ''}`} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
</div>
{/* Tech Stack Badges */}
<div className="px-4 pb-3 flex flex-wrap gap-2">
{['TypeScript', 'React', 'Vite', 'Tailwind CSS', 'Zustand'].map((tech) => (
<span key={tech} className="px-2 py-1 text-xs rounded-full bg-primary/10 text-primary">
{tech}
</span>
))}
</div>
{/* Expanded Content */}
{expanded && (
<div className="p-4 border-t bg-muted/20 space-y-4">
<div>
<h5 className="text-xs font-semibold mb-2">Architecture</h5>
<div className="text-sm text-muted-foreground space-y-1">
<div> Component-based UI architecture</div>
<div> Centralized state management</div>
<div> RESTful API integration</div>
</div>
</div>
<div>
<h5 className="text-xs font-semibold mb-2">Key Components</h5>
<div className="grid grid-cols-2 gap-2 text-sm">
{['Session Manager', 'Dashboard', 'Task Scheduler', 'Analytics'].map((comp) => (
<div key={comp} className="flex items-center gap-2">
<div className="w-1.5 h-1.5 rounded-full bg-primary"/>
{comp}
</div>
))}
</div>
</div>
</div>
)}
</div>
</div>
)
}

View File

@@ -0,0 +1,60 @@
/**
* Queue Item Status Demo
* Shows all possible queue item states
*/
import React from 'react'
export default function QueueItemStatusDemo() {
const itemStates = [
{ status: 'pending', issueId: 'ISSUE-101', sessionKey: null },
{ status: 'executing', issueId: 'ISSUE-102', sessionKey: 'cli-session-abc' },
{ status: 'completed', issueId: 'ISSUE-103', sessionKey: 'cli-session-def' },
{ status: 'blocked', issueId: 'ISSUE-104', sessionKey: null },
{ status: 'failed', issueId: 'ISSUE-105', sessionKey: 'cli-session-ghi' },
]
const statusConfig = {
pending: { icon: '○', color: 'text-gray-400', bg: 'bg-gray-500/10', label: 'Pending' },
executing: { icon: '▶', color: 'text-blue-500', bg: 'bg-blue-500/10', label: 'Executing' },
completed: { icon: '✓', color: 'text-green-500', bg: 'bg-green-500/10', label: 'Completed' },
blocked: { icon: '✕', color: 'text-red-500', bg: 'bg-red-500/10', label: 'Blocked' },
failed: { icon: '!', color: 'text-red-500', bg: 'bg-red-500/10', label: 'Failed' },
}
return (
<div className="p-6 bg-background space-y-4">
<h3 className="text-sm font-semibold">Queue Item Status States</h3>
<div className="space-y-2">
{itemStates.map((item) => {
const config = statusConfig[item.status as keyof typeof statusConfig]
return (
<div key={item.status} className="border rounded-lg p-4 flex items-center gap-4">
<span className={`text-2xl ${config.color}`}>{config.icon}</span>
<div className="flex-1">
<div className="flex items-center gap-2">
<span className="font-medium">{item.issueId}</span>
<span className={`text-xs px-2 py-0.5 rounded-full ${config.bg} ${config.color}`}>
{config.label}
</span>
</div>
{item.sessionKey && (
<div className="text-sm text-muted-foreground mt-1">
Bound session: <code className="text-xs bg-muted px-1 rounded">{item.sessionKey}</code>
</div>
)}
</div>
{item.status === 'executing' && (
<div className="flex items-center gap-2">
<div className="w-24 h-2 bg-muted rounded-full overflow-hidden">
<div className="h-full bg-blue-500 animate-pulse" style={{ width: '60%' }}/>
</div>
<span className="text-xs text-muted-foreground">60%</span>
</div>
)}
</div>
)
})}
</div>
</div>
)
}

View File

@@ -0,0 +1,164 @@
/**
* Queue Management Demo
* Shows scheduler controls and queue items list
*/
import React, { useState, useEffect } from 'react'
export default function QueueManagementDemo() {
const [schedulerStatus, setSchedulerStatus] = useState('idle')
const [progress, setProgress] = useState(0)
const queueItems = [
{ id: '1', status: 'completed', issueId: 'ISSUE-1', sessionKey: 'session-1' },
{ id: '2', status: 'executing', issueId: 'ISSUE-2', sessionKey: 'session-2' },
{ id: '3', status: 'pending', issueId: 'ISSUE-3', sessionKey: null },
{ id: '4', status: 'pending', issueId: 'ISSUE-4', sessionKey: null },
{ id: '5', status: 'blocked', issueId: 'ISSUE-5', sessionKey: null },
]
const statusConfig = {
idle: { label: 'Idle', color: 'bg-gray-500/20 text-gray-600 border-gray-500' },
running: { label: 'Running', color: 'bg-green-500/20 text-green-600 border-green-500' },
paused: { label: 'Paused', color: 'bg-amber-500/20 text-amber-600 border-amber-500' },
}
const itemStatusConfig = {
completed: { icon: '✓', color: 'text-green-500', label: 'Completed' },
executing: { icon: '▶', color: 'text-blue-500', label: 'Executing' },
pending: { icon: '○', color: 'text-gray-400', label: 'Pending' },
blocked: { icon: '✕', color: 'text-red-500', label: 'Blocked' },
failed: { icon: '!', color: 'text-red-500', label: 'Failed' },
}
useEffect(() => {
if (schedulerStatus === 'running') {
const interval = setInterval(() => {
setProgress((p) => (p >= 100 ? 0 : p + 10))
}, 500)
return () => clearInterval(interval)
}
}, [schedulerStatus])
const handleStart = () => {
if (schedulerStatus === 'idle' || schedulerStatus === 'paused') {
setSchedulerStatus('running')
}
}
const handlePause = () => {
if (schedulerStatus === 'running') {
setSchedulerStatus('paused')
}
}
const handleStop = () => {
setSchedulerStatus('idle')
setProgress(0)
}
const currentConfig = statusConfig[schedulerStatus as keyof typeof statusConfig]
return (
<div className="p-6 bg-background space-y-6">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h3 className="text-lg font-semibold">Queue Management</h3>
<p className="text-sm text-muted-foreground">Manage issue execution queue</p>
</div>
</div>
{/* Scheduler Status Bar */}
<div className="border rounded-lg p-4 space-y-4">
<div className="flex items-center justify-between">
<span className={`px-3 py-1 rounded text-xs font-medium border ${currentConfig.color}`}>
{currentConfig.label}
</span>
<div className="flex items-center gap-4 text-sm text-muted-foreground">
<span>{queueItems.filter((i) => i.status === 'completed').length}/{queueItems.length} items</span>
<span>2/2 concurrent</span>
</div>
</div>
{/* Progress Bar */}
{schedulerStatus === 'running' && (
<div className="space-y-1">
<div className="h-2 bg-muted rounded-full overflow-hidden">
<div
className="h-full bg-green-500 rounded-full transition-all"
style={{ width: `${progress}%` }}
/>
</div>
<span className="text-xs text-muted-foreground">{progress}% complete</span>
</div>
)}
{/* Scheduler Controls */}
<div className="flex items-center gap-2">
{(schedulerStatus === 'idle' || schedulerStatus === 'paused') && (
<button
onClick={handleStart}
className="px-4 py-2 text-sm bg-green-500 text-white rounded hover:bg-green-600 flex items-center gap-2"
>
<span></span> Start
</button>
)}
{schedulerStatus === 'running' && (
<button
onClick={handlePause}
className="px-4 py-2 text-sm bg-amber-500 text-white rounded hover:bg-amber-600 flex items-center gap-2"
>
<span></span> Pause
</button>
)}
{schedulerStatus !== 'idle' && (
<button
onClick={handleStop}
className="px-4 py-2 text-sm bg-red-500 text-white rounded hover:bg-red-600 flex items-center gap-2"
>
<span></span> Stop
</button>
)}
<button className="px-4 py-2 text-sm border rounded hover:bg-accent">
Config
</button>
</div>
</div>
{/* Queue Items List */}
<div className="border rounded-lg">
<div className="px-4 py-3 border-b bg-muted/30">
<h4 className="text-sm font-semibold">Queue Items</h4>
</div>
<div className="divide-y max-h-80 overflow-auto">
{queueItems.map((item) => {
const config = itemStatusConfig[item.status as keyof typeof itemStatusConfig]
return (
<div key={item.id} className="px-4 py-3 flex items-center gap-4 hover:bg-accent/50">
<span className={`text-lg ${config.color}`}>{config.icon}</span>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<span className="text-sm font-medium">{item.issueId}</span>
<span className={`text-xs px-2 py-0.5 rounded-full ${config.color} bg-opacity-10`}>
{config.label}
</span>
</div>
{item.sessionKey && (
<div className="text-xs text-muted-foreground mt-1">
Session: {item.sessionKey}
</div>
)}
</div>
{item.status === 'executing' && (
<div className="w-20 h-1.5 bg-muted rounded-full overflow-hidden">
<div className="h-full bg-blue-500 animate-pulse" style={{ width: '60%' }}/>
</div>
)}
</div>
)
})}
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,86 @@
/**
* Resizable Panes Demo
* Simulates the Allotment resizable split behavior
*/
import React, { useState, useEffect } from 'react'
export default function ResizablePanesDemo() {
const [leftWidth, setLeftWidth] = useState(240)
const [rightWidth, setRightWidth] = useState(280)
const [isDragging, setIsDragging] = useState<string | null>(null)
const handleDragStart = (side: string) => (e: React.MouseEvent) => {
setIsDragging(side)
e.preventDefault()
}
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (isDragging === 'left') {
setLeftWidth(Math.max(180, Math.min(320, e.clientX - 24)))
} else if (isDragging === 'right') {
setRightWidth(Math.max(200, Math.min(400, window.innerWidth - e.clientX - 24)))
}
}
const handleMouseUp = () => setIsDragging(null)
if (isDragging) {
window.addEventListener('mousemove', handleMouseMove)
window.addEventListener('mouseup', handleMouseUp)
return () => {
window.removeEventListener('mousemove', handleMouseMove)
window.removeEventListener('mouseup', handleMouseUp)
}
}
}, [isDragging])
return (
<div className="h-[400px] flex bg-background border rounded-lg overflow-hidden">
{/* Left Sidebar */}
<div style={{ width: leftWidth }} className="border-r flex flex-col min-w-[180px]">
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
Session Groups
</div>
<div className="flex-1 p-2 text-sm space-y-1">
{['Active Sessions', 'Completed'].map((g) => (
<div key={g} className="px-2 py-1 hover:bg-accent rounded cursor-pointer">{g}</div>
))}
</div>
</div>
{/* Left Drag Handle */}
<div
onMouseDown={handleDragStart('left')}
className={`w-1 bg-border hover:bg-primary cursor-col-resize transition-colors ${
isDragging === 'left' ? 'bg-primary' : ''
}`}
/>
{/* Main Content */}
<div className="flex-1 bg-muted/20 flex items-center justify-center">
<span className="text-sm text-muted-foreground">Terminal Grid Area</span>
</div>
{/* Right Drag Handle */}
<div
onMouseDown={handleDragStart('right')}
className={`w-1 bg-border hover:bg-primary cursor-col-resize transition-colors ${
isDragging === 'right' ? 'bg-primary' : ''
}`}
/>
{/* Right Sidebar */}
<div style={{ width: rightWidth }} className="border-l flex flex-col min-w-[200px]">
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
Project Files
</div>
<div className="flex-1 p-2 text-sm space-y-1">
{['src/', 'docs/', 'tests/'].map((f) => (
<div key={f} className="px-2 py-1 hover:bg-accent rounded cursor-pointer">{f}</div>
))}
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,110 @@
/**
* Scheduler Config Demo
* Interactive configuration panel
*/
import React, { useState } from 'react'
export default function SchedulerConfigDemo() {
const [config, setConfig] = useState({
maxConcurrentSessions: 2,
sessionIdleTimeoutMs: 60000,
resumeKeySessionBindingTimeoutMs: 300000,
})
const formatMs = (ms: number) => {
if (ms >= 60000) return `${ms / 60000}m`
if (ms >= 1000) return `${ms / 1000}s`
return `${ms}ms`
}
return (
<div className="p-6 bg-background space-y-6 max-w-md">
<div className="flex items-center justify-between">
<h3 className="text-sm font-semibold">Scheduler Configuration</h3>
<button className="px-3 py-1.5 text-xs bg-primary text-primary-foreground rounded hover:opacity-90">
Save
</button>
</div>
<div className="space-y-4">
{/* Max Concurrent Sessions */}
<div className="space-y-2">
<label className="text-sm font-medium">Max Concurrent Sessions</label>
<div className="flex items-center gap-3">
<input
type="range"
min="1"
max="8"
value={config.maxConcurrentSessions}
onChange={(e) => setConfig({ ...config, maxConcurrentSessions: parseInt(e.target.value) })}
className="flex-1"
/>
<span className="text-sm font-medium w-8 text-center">{config.maxConcurrentSessions}</span>
</div>
<p className="text-xs text-muted-foreground">
Maximum number of sessions to run simultaneously
</p>
</div>
{/* Session Idle Timeout */}
<div className="space-y-2">
<label className="text-sm font-medium">Session Idle Timeout</label>
<div className="flex items-center gap-3">
<input
type="range"
min="10000"
max="300000"
step="10000"
value={config.sessionIdleTimeoutMs}
onChange={(e) => setConfig({ ...config, sessionIdleTimeoutMs: parseInt(e.target.value) })}
className="flex-1"
/>
<span className="text-sm font-medium w-12 text-right">{formatMs(config.sessionIdleTimeoutMs)}</span>
</div>
<p className="text-xs text-muted-foreground">
Time before idle session is terminated
</p>
</div>
{/* Resume Key Binding Timeout */}
<div className="space-y-2">
<label className="text-sm font-medium">Resume Key Binding Timeout</label>
<div className="flex items-center gap-3">
<input
type="range"
min="60000"
max="600000"
step="60000"
value={config.resumeKeySessionBindingTimeoutMs}
onChange={(e) => setConfig({ ...config, resumeKeySessionBindingTimeoutMs: parseInt(e.target.value) })}
className="flex-1"
/>
<span className="text-sm font-medium w-12 text-right">{formatMs(config.resumeKeySessionBindingTimeoutMs)}</span>
</div>
<p className="text-xs text-muted-foreground">
Time to preserve resume key session binding
</p>
</div>
</div>
{/* Current Config Display */}
<div className="border rounded-lg p-4 bg-muted/30">
<h4 className="text-xs font-semibold mb-3">Current Configuration</h4>
<dl className="space-y-2 text-sm">
<div className="flex justify-between">
<dt className="text-muted-foreground">Max Concurrent</dt>
<dd className="font-medium">{config.maxConcurrentSessions} sessions</dd>
</div>
<div className="flex justify-between">
<dt className="text-muted-foreground">Idle Timeout</dt>
<dd className="font-medium">{formatMs(config.sessionIdleTimeoutMs)}</dd>
</div>
<div className="flex justify-between">
<dt className="text-muted-foreground">Binding Timeout</dt>
<dd className="font-medium">{formatMs(config.resumeKeySessionBindingTimeoutMs)}</dd>
</div>
</dl>
</div>
</div>
)
}

View File

@@ -0,0 +1,108 @@
/**
* Session Carousel Demo
* Auto-rotating session cards with navigation
*/
import React, { useState, useEffect } from 'react'
export default function SessionCarousel() {
const [currentIndex, setCurrentIndex] = useState(0)
const sessions = [
{
name: 'Feature: User Authentication',
status: 'running',
tasks: [
{ name: 'Implement login form', status: 'completed' },
{ name: 'Add OAuth provider', status: 'in-progress' },
{ name: 'Create session management', status: 'pending' },
],
},
{
name: 'Bug Fix: Memory Leak',
status: 'running',
tasks: [
{ name: 'Identify leak source', status: 'completed' },
{ name: 'Fix cleanup handlers', status: 'in-progress' },
{ name: 'Add unit tests', status: 'pending' },
],
},
{
name: 'Refactor: API Layer',
status: 'planning',
tasks: [
{ name: 'Design new interface', status: 'pending' },
{ name: 'Migrate existing endpoints', status: 'pending' },
{ name: 'Update documentation', status: 'pending' },
],
},
]
const statusColors = {
completed: 'bg-green-500',
'in-progress': 'bg-amber-500',
pending: 'bg-muted',
}
useEffect(() => {
const timer = setInterval(() => {
setCurrentIndex((i) => (i + 1) % sessions.length)
}, 5000)
return () => clearInterval(timer)
}, [sessions.length])
return (
<div className="p-6 bg-background">
<h3 className="text-sm font-semibold mb-4">Session Carousel (auto-rotates every 5s)</h3>
<div className="border rounded-lg p-4 bg-card">
<div className="flex items-center justify-between mb-3">
<span className="text-sm font-medium">Session {currentIndex + 1} of {sessions.length}</span>
<div className="flex gap-1">
{sessions.map((_, i) => (
<button
key={i}
onClick={() => setCurrentIndex(i)}
className={`w-2 h-2 rounded-full transition-colors ${
i === currentIndex ? 'bg-primary' : 'bg-muted-foreground/30'
}`}
/>
))}
</div>
</div>
<div className="p-4 bg-accent/20 rounded border">
<div className="flex items-center justify-between mb-3">
<span className="font-medium">{sessions[currentIndex].name}</span>
<span className={`text-xs px-2 py-1 rounded-full ${
sessions[currentIndex].status === 'running' ? 'bg-green-500/20 text-green-600' : 'bg-blue-500/20 text-blue-600'
}`}>
{sessions[currentIndex].status}
</span>
</div>
<div className="space-y-2">
{sessions[currentIndex].tasks.map((task, i) => (
<div key={i} className="flex items-center gap-2 text-sm">
<div className={`w-3 h-3 rounded ${statusColors[task.status]}`}/>
<span className={task.status === 'pending' ? 'text-muted-foreground' : ''}>{task.name}</span>
</div>
))}
</div>
</div>
<div className="flex justify-between mt-3">
<button
onClick={() => setCurrentIndex((i) => (i - 1 + sessions.length) % sessions.length)}
className="px-3 py-1.5 text-sm border rounded-md hover:bg-accent"
>
Previous
</button>
<button
onClick={() => setCurrentIndex((i) => (i + 1) % sessions.length)}
className="px-3 py-1.5 text-sm border rounded-md hover:bg-accent"
>
Next
</button>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,122 @@
/**
* Terminal Dashboard Overview Demo
* Shows the three-column layout with resizable panes and toolbar
*/
import React, { useState } from 'react'
export default function TerminalDashboardOverview() {
const [fileSidebarOpen, setFileSidebarOpen] = useState(true)
const [sessionSidebarOpen, setSessionSidebarOpen] = useState(true)
const [activePanel, setActivePanel] = useState<string | null>(null)
return (
<div className="h-[600px] flex flex-col bg-background relative">
{/* Toolbar */}
<div className="flex items-center justify-between px-3 py-2 border-b bg-muted/30">
<div className="flex items-center gap-2">
<span className="text-sm font-medium">Terminal Dashboard</span>
</div>
<div className="flex items-center gap-1">
{['Sessions', 'Files', 'Issues', 'Queue', 'Inspector', 'Scheduler'].map((item) => (
<button
key={item}
onClick={() => {
if (item === 'Sessions') setSessionSidebarOpen(!sessionSidebarOpen)
else if (item === 'Files') setFileSidebarOpen(!fileSidebarOpen)
else setActivePanel(activePanel === item.toLowerCase() ? null : item.toLowerCase())
}}
className={`px-2 py-1 text-xs rounded transition-colors ${
(item === 'Sessions' && sessionSidebarOpen) ||
(item === 'Files' && fileSidebarOpen) ||
activePanel === item.toLowerCase()
? 'bg-primary text-primary-foreground'
: 'hover:bg-accent'
}`}
>
{item}
</button>
))}
</div>
</div>
{/* Main Layout */}
<div className="flex-1 flex min-h-0">
{/* Session Sidebar */}
{sessionSidebarOpen && (
<div className="w-60 border-r flex flex-col">
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
Session Groups
</div>
<div className="flex-1 p-2 space-y-1 text-sm overflow-auto">
{['Active Sessions', 'Completed', 'Archived'].map((group) => (
<div key={group}>
<div className="flex items-center gap-1 px-2 py-1 rounded hover:bg-accent cursor-pointer">
<span className="text-xs"></span>
<span>{group}</span>
</div>
<div className="ml-4 space-y-0.5">
<div className="px-2 py-1 text-xs text-muted-foreground hover:bg-accent rounded cursor-pointer">
Session 1
</div>
<div className="px-2 py-1 text-xs text-muted-foreground hover:bg-accent rounded cursor-pointer">
Session 2
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* Terminal Grid */}
<div className="flex-1 bg-muted/20 p-2">
<div className="grid grid-cols-2 grid-rows-2 gap-2 h-full">
{[1, 2, 3, 4].map((i) => (
<div key={i} className="bg-background border rounded p-3 font-mono text-xs">
<div className="text-green-500 mb-2">$ Terminal {i}</div>
<div className="text-muted-foreground">
<div>Working directory: /project</div>
<div>Type a command to begin...</div>
</div>
</div>
))}
</div>
</div>
{/* File Sidebar */}
{fileSidebarOpen && (
<div className="w-64 border-l flex flex-col">
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
Project Files
</div>
<div className="flex-1 p-2 text-sm overflow-auto">
<div className="space-y-1">
{['src', 'docs', 'tests', 'package.json', 'README.md'].map((item) => (
<div key={item} className="px-2 py-1 rounded hover:bg-accent cursor-pointer flex items-center gap-2">
<span className="text-xs text-muted-foreground">📁</span>
{item}
</div>
))}
</div>
</div>
</div>
)}
</div>
{/* Floating Panel */}
{activePanel && (
<div className="absolute top-12 right-4 w-80 bg-background border rounded-lg shadow-lg">
<div className="flex items-center justify-between px-3 py-2 border-b">
<span className="text-sm font-medium capitalize">{activePanel} Panel</span>
<button onClick={() => setActivePanel(null)} className="text-xs hover:bg-accent px-2 py-1 rounded">
</button>
</div>
<div className="p-4 text-sm text-muted-foreground">
{activePanel} content placeholder
</div>
</div>
)}
</div>
)
}

View File

@@ -0,0 +1,48 @@
/**
* Terminal Layout Presets Demo
* Interactive layout preset buttons
*/
import React, { useState } from 'react'
export default function TerminalLayoutPresets() {
const [layout, setLayout] = useState('grid-2x2')
const layouts = {
single: 'grid-cols-1 grid-rows-1',
'split-h': 'grid-cols-2 grid-rows-1',
'split-v': 'grid-cols-1 grid-rows-2',
'grid-2x2': 'grid-cols-2 grid-rows-2',
}
return (
<div className="p-6 bg-background space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-sm font-semibold">Terminal Layout Presets</h3>
<div className="flex gap-2">
{Object.keys(layouts).map((preset) => (
<button
key={preset}
onClick={() => setLayout(preset)}
className={`px-3 py-1.5 text-xs rounded transition-colors ${
layout === preset
? 'bg-primary text-primary-foreground'
: 'border hover:bg-accent'
}`}
>
{preset.replace('-', ' ').toUpperCase()}
</button>
))}
</div>
</div>
<div className={`grid gap-2 h-64 ${layouts[layout]}`}>
{Array.from({ length: layout === 'single' ? 1 : layout.includes('2x') ? 4 : 2 }).map((_, i) => (
<div key={i} className="bg-muted/20 border rounded p-4 font-mono text-xs">
<div className="text-green-500">$ Terminal {i + 1}</div>
<div className="text-muted-foreground mt-1">Ready for input...</div>
</div>
))}
</div>
</div>
)
}

View File

@@ -0,0 +1,57 @@
/**
* Badge Variants Demo
* Shows all available badge variants
*/
import React from 'react'
export default function BadgeVariantsDemo() {
const variants = [
{ name: 'default', class: 'bg-primary text-primary-foreground' },
{ name: 'secondary', class: 'bg-secondary text-secondary-foreground' },
{ name: 'destructive', class: 'bg-destructive text-destructive-foreground' },
{ name: 'outline', class: 'border text-foreground' },
{ name: 'success', class: 'bg-success text-white' },
{ name: 'warning', class: 'bg-warning text-white' },
{ name: 'info', class: 'bg-info text-white' },
{ name: 'review', class: 'bg-purple-500 text-white' },
{ name: 'gradient', class: 'bg-gradient-to-r from-blue-500 to-purple-500 text-white' },
]
return (
<div className="p-6 bg-background space-y-6">
<h3 className="text-sm font-semibold">Badge Variants</h3>
<div className="space-y-4">
<div className="flex flex-wrap gap-3">
{variants.map((v) => (
<span
key={v.name}
className={`inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold ${v.class}`}
>
{v.name}
</span>
))}
</div>
</div>
{/* Usage Examples */}
<div className="space-y-3">
<h4 className="text-sm font-medium">Usage Examples</h4>
<div className="space-y-2">
<div className="flex items-center gap-2 p-2 border rounded">
<span className="font-medium">Status:</span>
<span className="inline-flex items-center rounded-full bg-success px-2 py-0.5 text-xs text-white">Active</span>
</div>
<div className="flex items-center gap-2 p-2 border rounded">
<span className="font-medium">Priority:</span>
<span className="inline-flex items-center rounded-full bg-destructive px-2 py-0.5 text-xs text-white">High</span>
</div>
<div className="flex items-center gap-2 p-2 border rounded">
<span className="font-medium">Type:</span>
<span className="inline-flex items-center rounded-full bg-info px-2 py-0.5 text-xs text-white">Feature</span>
</div>
</div>
</div>
</div>
)
}

View File

@@ -1,52 +1,80 @@
import React from 'react'
import { Button } from '@/components/ui/Button'
/**
* Button Variants Demo
* Shows all 8 visual variants and 4 sizes of the Button component
*
* Variants include:
* - default: Primary brand color button
* - destructive: Red danger button
* - outline: Bordered light button
* - secondary: Gray secondary button
* - ghost: Transparent hover button
* - link: Link-style button
* - gradient: Brand gradient button
* - gradientPrimary: Primary gradient button
*
* Sizes include:
* - default: Standard size (h-10)
* - sm: Small size (h-9)
* - lg: Large size (h-11)
* - icon: Square icon size (h-10 w-10)
* Shows all visual variants of the button component
*/
export default function ButtonVariants() {
import React, { useState } from 'react'
export default function ButtonVariantsDemo() {
const [variant, setVariant] = useState('default')
const variants = ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link', 'gradient']
const getButtonClass = (v: string) => {
const base = 'px-4 py-2 rounded-md text-sm transition-colors'
switch (v) {
case 'default': return `${base} bg-primary text-primary-foreground hover:opacity-90`
case 'destructive': return `${base} bg-destructive text-destructive-foreground hover:opacity-90`
case 'outline': return `${base} border bg-background hover:bg-accent`
case 'secondary': return `${base} bg-secondary text-secondary-foreground hover:opacity-80`
case 'ghost': return `${base} hover:bg-accent`
case 'link': return `${base} text-primary underline-offset-4 hover:underline`
case 'gradient': return `${base} bg-gradient-to-r from-blue-500 to-purple-500 text-white hover:opacity-90`
default: return base
}
}
return (
<div className="flex flex-col gap-6 p-4">
{/* Variants Section */}
<div>
<h3 className="text-sm font-semibold mb-3 text-muted-foreground">Variants</h3>
<div className="flex flex-wrap gap-3">
<Button variant="default">Default</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button variant="gradient">Gradient</Button>
<Button variant="gradientPrimary">Gradient Primary</Button>
<div className="p-6 bg-background space-y-6">
<h3 className="text-sm font-semibold">Button Variants</h3>
{/* Variant Selector */}
<div className="space-y-3">
<label className="text-sm font-medium">Select Variant</label>
<div className="flex flex-wrap gap-2">
{variants.map((v) => (
<button
key={v}
onClick={() => setVariant(v)}
className={`px-3 py-1.5 text-xs rounded capitalize transition-colors ${
variant === v ? 'bg-primary text-primary-foreground' : 'border hover:bg-accent'
}`}
>
{v}
</button>
))}
</div>
</div>
{/* Sizes Section */}
<div>
<h3 className="text-sm font-semibold mb-3 text-muted-foreground">Sizes</h3>
<div className="flex flex-wrap items-center gap-3">
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button size="icon">🔍</Button>
{/* Preview */}
<div className="space-y-3">
<label className="text-sm font-medium">Preview</label>
<div className="p-4 border rounded-lg bg-muted/20">
<button className={getButtonClass(variant)}>
Button
</button>
</div>
</div>
{/* All Variants */}
<div className="space-y-3">
<label className="text-sm font-medium">All Variants</label>
<div className="flex flex-wrap gap-3 p-4 border rounded-lg">
{variants.map((v) => (
<button key={v} className={getButtonClass(v)}>
{v.charAt(0).toUpperCase() + v.slice(1)}
</button>
))}
</div>
</div>
{/* Sizes */}
<div className="space-y-3">
<label className="text-sm font-medium">Sizes</label>
<div className="flex items-center gap-3 flex-wrap p-4 border rounded-lg">
<button className={`${getButtonClass(variant)} h-8 px-3 text-xs`}>Small</button>
<button className={`${getButtonClass(variant)} h-10 px-4`}>Default</button>
<button className={`${getButtonClass(variant)} h-11 px-8`}>Large</button>
<button className={`${getButtonClass(variant)} h-10 w-10`}></button>
</div>
</div>
</div>

View File

@@ -0,0 +1,71 @@
/**
* Card Variants Demo
* Shows different card layouts
*/
import React from 'react'
export default function CardVariantsDemo() {
return (
<div className="p-6 bg-background space-y-6">
<h3 className="text-sm font-semibold">Card Variants</h3>
<div className="grid md:grid-cols-2 gap-4">
{/* Basic Card */}
<div className="border rounded-lg">
<div className="p-4 border-b">
<h4 className="font-semibold">Basic Card</h4>
<p className="text-sm text-muted-foreground">With header and content</p>
</div>
<div className="p-4">
<p className="text-sm">Card content goes here.</p>
</div>
</div>
{/* Card with Footer */}
<div className="border rounded-lg">
<div className="p-4 border-b">
<h4 className="font-semibold">Card with Footer</h4>
</div>
<div className="p-4">
<p className="text-sm">Main content area.</p>
</div>
<div className="p-4 border-t bg-muted/20">
<div className="flex gap-2">
<button className="px-3 py-1.5 text-xs bg-primary text-primary-foreground rounded">Action</button>
<button className="px-3 py-1.5 text-xs border rounded">Cancel</button>
</div>
</div>
</div>
{/* Gradient Border Card */}
<div className="border-2 border-transparent bg-gradient-to-r from-blue-500 to-purple-500 p-[2px] rounded-lg">
<div className="bg-background rounded-lg p-4">
<h4 className="font-semibold">Gradient Border</h4>
<p className="text-sm text-muted-foreground mt-1">Card with gradient border effect.</p>
</div>
</div>
{/* Settings Card */}
<div className="border rounded-lg">
<div className="p-4 border-b">
<h4 className="font-semibold">Settings</h4>
</div>
<div className="p-4 space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm">Enable notifications</span>
<div className="w-9 h-5 bg-primary rounded-full relative">
<div className="absolute right-[2px] top-[2px] w-4 h-4 bg-white rounded-full" />
</div>
</div>
<div className="flex items-center justify-between">
<span className="text-sm">Dark mode</span>
<div className="w-9 h-5 bg-muted rounded-full relative">
<div className="absolute left-[2px] top-[2px] w-4 h-4 bg-white rounded-full" />
</div>
</div>
</div>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,79 @@
/**
* Checkbox Variants Demo
* Shows different checkbox states
*/
import React, { useState } from 'react'
export default function CheckboxVariantsDemo() {
const [checked, setChecked] = useState({ a: true, b: false, c: true })
return (
<div className="p-6 bg-background space-y-6">
<h3 className="text-sm font-semibold">Checkbox States</h3>
<div className="space-y-4">
{/* Checked */}
<label className="flex items-center gap-3 cursor-pointer">
<input
type="checkbox"
checked={checked.a}
onChange={(e) => setChecked({ ...checked, a: e.target.checked })}
className="h-4 w-4 rounded border border-primary accent-primary"
/>
<span className="text-sm">Checked checkbox</span>
</label>
{/* Unchecked */}
<label className="flex items-center gap-3 cursor-pointer">
<input
type="checkbox"
checked={checked.b}
onChange={(e) => setChecked({ ...checked, b: e.target.checked })}
className="h-4 w-4 rounded border border-primary accent-primary"
/>
<span className="text-sm">Unchecked checkbox</span>
</label>
{/* Disabled */}
<label className="flex items-center gap-3 cursor-not-allowed opacity-50">
<input
type="checkbox"
disabled
className="h-4 w-4 rounded border border-primary"
/>
<span className="text-sm">Disabled checkbox</span>
</label>
{/* Disabled Checked */}
<label className="flex items-center gap-3 cursor-not-allowed opacity-50">
<input
type="checkbox"
disabled
defaultChecked
className="h-4 w-4 rounded border border-primary accent-primary"
/>
<span className="text-sm">Disabled checked checkbox</span>
</label>
</div>
{/* Usage Example */}
<div className="space-y-3">
<h4 className="text-sm font-medium">Usage Example</h4>
<div className="p-4 border rounded-lg space-y-2">
<label className="flex items-center gap-3 cursor-pointer">
<input type="checkbox" className="h-4 w-4 rounded border accent-primary" />
<span className="text-sm">Accept terms and conditions</span>
</label>
<label className="flex items-center gap-3 cursor-pointer">
<input type="checkbox" className="h-4 w-4 rounded border accent-primary" />
<span className="text-sm">Subscribe to newsletter</span>
</label>
<label className="flex items-center gap-3 cursor-pointer">
<input type="checkbox" className="h-4 w-4 rounded border accent-primary" />
<span className="text-sm">Remember me</span>
</label>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,95 @@
/**
* Input Variants Demo
* Shows all input states
*/
import React, { useState } from 'react'
export default function InputVariantsDemo() {
const [value, setValue] = useState('')
return (
<div className="p-6 bg-background space-y-6">
<h3 className="text-sm font-semibold">Input States</h3>
<div className="grid md:grid-cols-2 gap-6">
{/* Default */}
<div className="space-y-2">
<label className="text-sm font-medium">Default</label>
<input
type="text"
placeholder="Enter text..."
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
</div>
{/* With Value */}
<div className="space-y-2">
<label className="text-sm font-medium">With Value</label>
<input
type="text"
value="John Doe"
readOnly
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
/>
</div>
{/* Error State */}
<div className="space-y-2">
<label className="text-sm font-medium">Error State</label>
<input
type="text"
placeholder="Invalid input"
className="flex h-10 w-full rounded-md border border-destructive bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-destructive"
/>
<p className="text-xs text-destructive">This field is required</p>
</div>
{/* Disabled */}
<div className="space-y-2">
<label className="text-sm font-medium">Disabled</label>
<input
type="text"
disabled
placeholder="Disabled input"
className="flex h-10 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm opacity-50 cursor-not-allowed"
/>
</div>
{/* With Icon */}
<div className="space-y-2">
<label className="text-sm font-medium">Search Input</label>
<div className="relative">
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">🔍</span>
<input
type="text"
placeholder="Search..."
className="flex h-10 w-full rounded-md border border-input bg-background pl-10 pr-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
</div>
</div>
{/* Controlled */}
<div className="space-y-2">
<label className="text-sm font-medium">Controlled Input</label>
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Type something..."
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
<p className="text-xs text-muted-foreground">Value: {value || '(empty)'}</p>
</div>
</div>
{/* Textarea */}
<div className="space-y-2">
<label className="text-sm font-medium">Textarea</label>
<textarea
placeholder="Enter multi-line text..."
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
</div>
</div>
)
}

View File

@@ -0,0 +1,101 @@
/**
* Select Variants Demo
* Shows different select configurations
*/
import React, { useState } from 'react'
export default function SelectVariantsDemo() {
const [selected, setSelected] = useState('')
return (
<div className="p-6 bg-background space-y-6">
<h3 className="text-sm font-semibold">Select Configurations</h3>
<div className="grid md:grid-cols-2 gap-6">
{/* Basic Select */}
<div className="space-y-2">
<label className="text-sm font-medium">Basic Select</label>
<select className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring">
<option value="">Choose an option</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
</div>
{/* With Labels */}
<div className="space-y-2">
<label className="text-sm font-medium">With Option Groups</label>
<select className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring">
<optgroup label="Fruits">
<option value="apple">Apple</option>
<option value="banana">Banana</option>
<option value="orange">Orange</option>
</optgroup>
<optgroup label="Vegetables">
<option value="carrot">Carrot</option>
<option value="broccoli">Broccoli</option>
</optgroup>
</select>
</div>
{/* Controlled Select */}
<div className="space-y-2">
<label className="text-sm font-medium">Controlled Select</label>
<select
value={selected}
onChange={(e) => setSelected(e.target.value)}
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
>
<option value="">Select...</option>
<option value="react">React</option>
<option value="vue">Vue</option>
<option value="angular">Angular</option>
</select>
<p className="text-xs text-muted-foreground">Selected: {selected || '(none)'}</p>
</div>
{/* Disabled Select */}
<div className="space-y-2">
<label className="text-sm font-medium">Disabled Select</label>
<select
disabled
className="flex h-10 w-full rounded-md border border-input bg-muted px-3 py-2 text-sm opacity-50 cursor-not-allowed"
>
<option value="">Disabled select</option>
<option value="1">Option 1</option>
</select>
</div>
</div>
{/* With Separators */}
<div className="space-y-2">
<label className="text-sm font-medium">With Separators</label>
<select className="flex h-10 w-full max-w-md rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring">
<option value="">Select an action</option>
<option value="edit">Edit</option>
<option value="copy">Copy</option>
<option value="move">Move</option>
{/* Visual separator via disabled option */}
<option disabled></option>
<option value="delete" className="text-destructive">Delete</option>
</select>
</div>
{/* Multiple Select */}
<div className="space-y-2">
<label className="text-sm font-medium">Multiple Select (Hold Ctrl/Cmd)</label>
<select
multiple
className="flex min-h-[100px] w-full max-w-md rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="js">JavaScript</option>
<option value="ts">TypeScript</option>
<option value="react">React</option>
</select>
</div>
</div>
)
}