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

@@ -55,144 +55,7 @@
## 实时演示
:::demo DashboardOverview
# dashboard-overview.tsx
/**
* 仪表板概览演示
* 显示带有小部件的主仪表板布局
*/
export function DashboardOverview() {
return (
<div className="space-y-6 p-6 bg-background min-h-[600px]">
{/* 头部 */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold">仪表板</h1>
<p className="text-sm text-muted-foreground">
项目概览和活动监控
</p>
</div>
<button className="px-3 py-1.5 text-sm border rounded-md hover:bg-accent">
刷新
</button>
</div>
{/* 工作流统计小部件 */}
<div className="border rounded-lg overflow-hidden">
<div className="p-4 border-b bg-muted/30">
<h2 className="font-semibold">项目概览与统计</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">统计数据</div>
<div className="grid grid-cols-2 gap-2">
{[
{ label: '活动会话', value: '12', color: 'text-blue-500' },
{ label: '总任务', value: '48', color: 'text-green-500' },
{ label: '已完成', value: '35', color: 'text-emerald-500' },
{ label: '待处理', 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">工作流状态</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>已完成70%</span>
</div>
</div>
</div>
<div className="space-y-3">
<div className="text-xs font-medium text-muted-foreground">最近会话</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">功能:身份验证流程</span>
<span className="text-xs px-2 py-0.5 rounded-full bg-green-500/20 text-green-600">运行中</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>实现登录表单</span>
</div>
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded bg-amber-500"/>
<span>添加 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">测试流程</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* 最近会话小部件 */}
<div className="border rounded-lg overflow-hidden">
<div className="border-b bg-muted/30">
<div className="flex gap-1 p-2">
{['所有任务', '工作流', '轻量任务'].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: '重构 UI 组件', status: '进行中', progress: 65 },
{ name: '修复登录 Bug', status: '待处理', progress: 0 },
{ name: '添加深色模式', status: '已完成', 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 === '已完成' ? 'bg-green-500/20 text-green-600' :
task.status === '进行中' ? '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>
)
}
:::
:::demo DashboardOverview #DashboardOverview.tsx :::
---
@@ -339,243 +202,15 @@ function ActivityFeed() {
### 统计卡片演示
:::demo MiniStatCards
# mini-stat-cards.tsx
/**
* 迷你统计卡片演示
* 带有迷你趋势图的独立统计卡片
*/
export function MiniStatCards() {
const stats = [
{ label: '活动会话', value: 12, trend: [8, 10, 9, 11, 10, 12, 12], color: 'blue' },
{ label: '总任务', value: 48, trend: [40, 42, 45, 44, 46, 47, 48], color: 'green' },
{ label: '已完成', value: 35, trend: [25, 28, 30, 32, 33, 34, 35], color: 'emerald' },
{ label: '待处理', value: 8, trend: [12, 10, 11, 9, 8, 7, 8], color: 'amber' },
{ label: '失败', value: 5, trend: [3, 4, 3, 5, 4, 5, 5], color: 'red' },
{ label: '今日活动', 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">带迷你趋势图的统计</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>
)
}
:::
:::demo MiniStatCards #MiniStatCards.tsx :::
### 项目信息横幅演示
:::demo ProjectInfoBanner
# project-info-banner.tsx
/**
* 项目信息横幅演示
* 带有技术栈的可展开项目信息
*/
export function ProjectInfoBanner() {
const [expanded, setExpanded] = React.useState(false)
return (
<div className="p-6 bg-background">
<h3 className="text-sm font-semibold mb-4">项目信息横幅</h3>
<div className="border rounded-lg overflow-hidden">
{/* 横幅头部 */}
<div className="p-4 bg-muted/30 flex items-center justify-between">
<div>
<h4 className="font-semibold">我的项目</h4>
<p className="text-sm text-muted-foreground">使用 React 构建的现代化 Web 应用</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>
{/* 技术栈徽章 */}
<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 && (
<div className="p-4 border-t bg-muted/20 space-y-4">
<div>
<h5 className="text-xs font-semibold mb-2">架构</h5>
<div className="text-sm text-muted-foreground space-y-1">
<div>• 基于组件的 UI 架构</div>
<div>• 集中式状态管理</div>
<div>• RESTful API 集成</div>
</div>
</div>
<div>
<h5 className="text-xs font-semibold mb-2">关键组件</h5>
<div className="grid grid-cols-2 gap-2 text-sm">
{['会话管理器', '仪表板', '任务调度器', '分析'].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>
)
}
:::
:::demo ProjectInfoBanner #ProjectInfoBanner.tsx :::
### 会话轮播演示
:::demo SessionCarousel
# session-carousel.tsx
/**
* 会话轮播演示
* 带有导航的自动轮播会话卡片
*/
export function SessionCarousel() {
const [currentIndex, setCurrentIndex] = React.useState(0)
const sessions = [
{
name: '功能:用户身份验证',
status: 'running',
tasks: [
{ name: '实现登录表单', status: 'completed' },
{ name: '添加 OAuth 提供商', status: 'in-progress' },
{ name: '创建会话管理', status: 'pending' },
],
},
{
name: 'Bug 修复:内存泄漏',
status: 'running',
tasks: [
{ name: '识别泄漏源', status: 'completed' },
{ name: '修复清理处理器', status: 'in-progress' },
{ name: '添加单元测试', status: 'pending' },
],
},
{
name: '重构API 层',
status: 'planning',
tasks: [
{ name: '设计新接口', status: 'pending' },
{ name: '迁移现有端点', status: 'pending' },
{ name: '更新文档', status: 'pending' },
],
},
]
const statusColors = {
completed: 'bg-green-500',
'in-progress': 'bg-amber-500',
pending: 'bg-muted',
}
React.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">会话轮播(每 5 秒自动轮播)</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">会话 {currentIndex + 1} / {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 === 'running' ? '运行中' : sessions[currentIndex].status === 'planning' ? '计划中' : 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"
>
← 上一页
</button>
<button
onClick={() => setCurrentIndex((i) => (i + 1) % sessions.length)}
className="px-3 py-1.5 text-sm border rounded-md hover:bg-accent"
>
下一页 →
</button>
</div>
</div>
</div>
)
}
:::
:::demo SessionCarousel #SessionCarousel.tsx :::
---

View File

@@ -48,129 +48,7 @@
## 实时演示
:::demo TerminalDashboardOverview
# terminal-dashboard-overview.tsx
/**
* Terminal Dashboard Overview Demo
* Shows the three-column layout with resizable panes and toolbar
*/
export function TerminalDashboardOverview() {
const [fileSidebarOpen, setFileSidebarOpen] = React.useState(true)
const [sessionSidebarOpen, setSessionSidebarOpen] = React.useState(true)
const [activePanel, setActivePanel] = React.useState(null)
return (
<div className="h-[600px] flex flex-col bg-background">
{/* 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>
)
}
:::
:::demo TerminalDashboardOverview #TerminalDashboardOverview.tsx :::
---
@@ -323,231 +201,15 @@ function CustomLayout() {
### 布局预设演示
:::demo TerminalLayoutPresets
# terminal-layout-presets.tsx
/**
* Terminal Layout Presets Demo
* Interactive layout preset buttons
*/
export function TerminalLayoutPresets() {
const [layout, setLayout] = React.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>
)
}
:::
:::demo TerminalLayoutPresets #TerminalLayoutPresets.tsx :::
### 浮动面板演示
:::demo FloatingPanelsDemo
# floating-panels-demo.tsx
/**
* Floating Panels Demo
* Mutually exclusive overlay panels
*/
export function FloatingPanelsDemo() {
const [activePanel, setActivePanel] = React.useState(null)
const panels = [
{ id: 'issues', title: 'Issues + Queue', side: 'left', width: 700 },
{ id: 'queue', title: 'Queue', side: 'right', width: 400 },
{ id: 'inspector', title: 'Inspector', side: 'right', width: 360 },
{ id: 'execution', title: 'Execution Monitor', side: 'right', width: 380 },
{ id: 'scheduler', title: 'Scheduler', side: 'right', width: 340 },
]
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">
{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>
)
}
:::
:::demo FloatingPanelsDemo #FloatingPanelsDemo.tsx :::
### 可调整大小窗格演示
:::demo ResizablePanesDemo
# resizable-panes-demo.tsx
/**
* Resizable Panes Demo
* Simulates the Allotment resizable split behavior
*/
export function ResizablePanesDemo() {
const [leftWidth, setLeftWidth] = React.useState(240)
const [rightWidth, setRightWidth] = React.useState(280)
const [isDragging, setIsDragging] = React.useState(null)
const handleDragStart = (side) => (e) => {
setIsDragging(side)
e.preventDefault()
}
React.useEffect(() => {
const handleMouseMove = (e) => {
if (isDragging === 'left') {
setLeftWidth(Math.max(180, Math.min(320, e.clientX)))
} else if (isDragging === 'right') {
setRightWidth(Math.max(200, Math.min(400, window.innerWidth - e.clientX)))
}
}
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">
<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">
<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>
)
}
:::
:::demo ResizablePanesDemo #ResizablePanesDemo.tsx :::
---