prjct-cli 0.18.2 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +82 -0
- package/CLAUDE.md +74 -211
- package/core/agentic/prompt-builder.ts +3 -7
- package/core/command-registry/optional-commands.ts +0 -20
- package/core/infrastructure/command-installer/command-installer.ts +8 -1
- package/core/infrastructure/command-installer/global-config.ts +31 -1
- package/core/infrastructure/command-installer/index.ts +1 -1
- package/core/infrastructure/setup.ts +3 -0
- package/package.json +3 -17
- package/templates/agentic/agents/uxui.md +210 -0
- package/templates/commands/bug.md +219 -41
- package/templates/commands/done.md +57 -258
- package/templates/commands/feature.md +368 -80
- package/templates/commands/now.md +72 -277
- package/templates/commands/ship.md +167 -246
- package/templates/commands/sync.md +62 -3
- package/templates/commands/test.md +160 -20
- package/templates/global/CLAUDE.md +40 -205
- package/templates/global/docs/agents.md +88 -0
- package/templates/global/docs/architecture.md +103 -0
- package/templates/global/docs/commands.md +98 -0
- package/templates/global/docs/validation.md +95 -0
- package/bin/dev.js +0 -216
- package/bin/serve.js +0 -361
- package/packages/web/README.md +0 -36
- package/packages/web/app/api/claude/sessions/route.ts +0 -44
- package/packages/web/app/api/claude/status/route.ts +0 -34
- package/packages/web/app/api/projects/[id]/icon/route.ts +0 -33
- package/packages/web/app/api/projects/[id]/momentum/route.ts +0 -257
- package/packages/web/app/api/projects/[id]/route.ts +0 -29
- package/packages/web/app/api/projects/[id]/stats/route.ts +0 -41
- package/packages/web/app/api/projects/[id]/status/route.ts +0 -21
- package/packages/web/app/api/projects/route.ts +0 -16
- package/packages/web/app/api/sessions/current/route.ts +0 -132
- package/packages/web/app/api/sessions/history/route.ts +0 -204
- package/packages/web/app/error.tsx +0 -34
- package/packages/web/app/favicon.ico +0 -0
- package/packages/web/app/globals.css +0 -198
- package/packages/web/app/layout.tsx +0 -53
- package/packages/web/app/loading.tsx +0 -7
- package/packages/web/app/not-found.tsx +0 -25
- package/packages/web/app/page.tsx +0 -12
- package/packages/web/app/project/[id]/code/layout.tsx +0 -18
- package/packages/web/app/project/[id]/code/page.tsx +0 -408
- package/packages/web/app/project/[id]/error.tsx +0 -41
- package/packages/web/app/project/[id]/loading.tsx +0 -9
- package/packages/web/app/project/[id]/not-found.tsx +0 -27
- package/packages/web/app/project/[id]/page.tsx +0 -384
- package/packages/web/app/project/[id]/reports/page.tsx +0 -59
- package/packages/web/app/project/[id]/reports/print/page.tsx +0 -58
- package/packages/web/app/sessions/page.tsx +0 -165
- package/packages/web/app/settings/page.tsx +0 -151
- package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +0 -2
- package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +0 -49
- package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +0 -8
- package/packages/web/components/ActivityTimeline/hooks/index.ts +0 -2
- package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +0 -9
- package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +0 -23
- package/packages/web/components/ActivityTimeline/index.ts +0 -2
- package/packages/web/components/AgentsCard/AgentsCard.tsx +0 -93
- package/packages/web/components/AgentsCard/AgentsCard.types.ts +0 -14
- package/packages/web/components/AgentsCard/index.ts +0 -2
- package/packages/web/components/AppSidebar/AppSidebar.tsx +0 -316
- package/packages/web/components/AppSidebar/index.ts +0 -1
- package/packages/web/components/BackLink/BackLink.tsx +0 -18
- package/packages/web/components/BackLink/BackLink.types.ts +0 -5
- package/packages/web/components/BackLink/index.ts +0 -2
- package/packages/web/components/BentoCard/BentoCard.constants.ts +0 -16
- package/packages/web/components/BentoCard/BentoCard.tsx +0 -48
- package/packages/web/components/BentoCard/BentoCard.types.ts +0 -15
- package/packages/web/components/BentoCard/index.ts +0 -2
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +0 -9
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +0 -18
- package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +0 -5
- package/packages/web/components/BentoCardSkeleton/index.ts +0 -2
- package/packages/web/components/BentoGrid/BentoGrid.tsx +0 -18
- package/packages/web/components/BentoGrid/BentoGrid.types.ts +0 -4
- package/packages/web/components/BentoGrid/index.ts +0 -2
- package/packages/web/components/BlockersCard/BlockersCard.tsx +0 -75
- package/packages/web/components/BlockersCard/BlockersCard.types.ts +0 -12
- package/packages/web/components/BlockersCard/index.ts +0 -2
- package/packages/web/components/CommandBar/CommandBar.tsx +0 -67
- package/packages/web/components/CommandBar/index.ts +0 -1
- package/packages/web/components/CommandButton/CommandButton.tsx +0 -46
- package/packages/web/components/CommandButton/index.ts +0 -1
- package/packages/web/components/ConnectionStatus/ConnectionStatus.tsx +0 -29
- package/packages/web/components/ConnectionStatus/index.ts +0 -1
- package/packages/web/components/DashboardContent/DashboardContent.tsx +0 -284
- package/packages/web/components/DashboardContent/index.ts +0 -1
- package/packages/web/components/DateGroup/DateGroup.tsx +0 -18
- package/packages/web/components/DateGroup/DateGroup.types.ts +0 -6
- package/packages/web/components/DateGroup/DateGroup.utils.ts +0 -11
- package/packages/web/components/DateGroup/index.ts +0 -2
- package/packages/web/components/EmptyState/EmptyState.tsx +0 -76
- package/packages/web/components/EmptyState/EmptyState.types.ts +0 -11
- package/packages/web/components/EmptyState/index.ts +0 -2
- package/packages/web/components/EventRow/EventRow.constants.ts +0 -10
- package/packages/web/components/EventRow/EventRow.tsx +0 -49
- package/packages/web/components/EventRow/EventRow.types.ts +0 -7
- package/packages/web/components/EventRow/EventRow.utils.ts +0 -49
- package/packages/web/components/EventRow/index.ts +0 -2
- package/packages/web/components/ExpandButton/ExpandButton.tsx +0 -18
- package/packages/web/components/ExpandButton/ExpandButton.types.ts +0 -6
- package/packages/web/components/ExpandButton/index.ts +0 -2
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +0 -14
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +0 -5
- package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +0 -13
- package/packages/web/components/HealthGradientBackground/index.ts +0 -2
- package/packages/web/components/HeroSection/HeroSection.tsx +0 -92
- package/packages/web/components/HeroSection/HeroSection.types.ts +0 -14
- package/packages/web/components/HeroSection/HeroSection.utils.ts +0 -11
- package/packages/web/components/HeroSection/hooks/index.ts +0 -2
- package/packages/web/components/HeroSection/hooks/useCountUp.ts +0 -45
- package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +0 -18
- package/packages/web/components/HeroSection/index.ts +0 -2
- package/packages/web/components/IdeasCard/IdeasCard.tsx +0 -115
- package/packages/web/components/IdeasCard/IdeasCard.types.ts +0 -10
- package/packages/web/components/IdeasCard/index.ts +0 -2
- package/packages/web/components/InsightMessage/InsightMessage.tsx +0 -9
- package/packages/web/components/InsightMessage/InsightMessage.types.ts +0 -3
- package/packages/web/components/InsightMessage/index.ts +0 -2
- package/packages/web/components/Logo/Logo.tsx +0 -65
- package/packages/web/components/Logo/index.ts +0 -1
- package/packages/web/components/MarkdownContent/MarkdownContent.tsx +0 -123
- package/packages/web/components/MarkdownContent/index.ts +0 -1
- package/packages/web/components/MasonryGrid/MasonryGrid.tsx +0 -18
- package/packages/web/components/MasonryGrid/index.ts +0 -1
- package/packages/web/components/MomentumWidget/MomentumWidget.tsx +0 -119
- package/packages/web/components/MomentumWidget/MomentumWidget.types.ts +0 -16
- package/packages/web/components/MomentumWidget/index.ts +0 -2
- package/packages/web/components/NowCard/NowCard.tsx +0 -118
- package/packages/web/components/NowCard/NowCard.types.ts +0 -16
- package/packages/web/components/NowCard/index.ts +0 -2
- package/packages/web/components/PageHeader/PageHeader.tsx +0 -24
- package/packages/web/components/PageHeader/index.ts +0 -1
- package/packages/web/components/ProgressRing/ProgressRing.constants.ts +0 -20
- package/packages/web/components/ProgressRing/ProgressRing.tsx +0 -51
- package/packages/web/components/ProgressRing/ProgressRing.types.ts +0 -11
- package/packages/web/components/ProgressRing/index.ts +0 -2
- package/packages/web/components/ProjectAvatar/ProjectAvatar.tsx +0 -54
- package/packages/web/components/ProjectAvatar/index.ts +0 -1
- package/packages/web/components/ProjectColorDot/ProjectColorDot.tsx +0 -37
- package/packages/web/components/ProjectColorDot/index.ts +0 -1
- package/packages/web/components/ProjectSelectorModal/ProjectSelectorModal.tsx +0 -104
- package/packages/web/components/ProjectSelectorModal/index.ts +0 -1
- package/packages/web/components/Providers/Providers.tsx +0 -48
- package/packages/web/components/Providers/index.ts +0 -1
- package/packages/web/components/QueueCard/QueueCard.tsx +0 -125
- package/packages/web/components/QueueCard/QueueCard.types.ts +0 -12
- package/packages/web/components/QueueCard/QueueCard.utils.ts +0 -12
- package/packages/web/components/QueueCard/index.ts +0 -2
- package/packages/web/components/RecoverCard/RecoverCard.tsx +0 -72
- package/packages/web/components/RecoverCard/RecoverCard.types.ts +0 -16
- package/packages/web/components/RecoverCard/index.ts +0 -2
- package/packages/web/components/RoadmapCard/RoadmapCard.tsx +0 -145
- package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +0 -16
- package/packages/web/components/RoadmapCard/index.ts +0 -2
- package/packages/web/components/ShipsCard/ShipsCard.tsx +0 -95
- package/packages/web/components/ShipsCard/ShipsCard.types.ts +0 -14
- package/packages/web/components/ShipsCard/ShipsCard.utils.ts +0 -4
- package/packages/web/components/ShipsCard/index.ts +0 -2
- package/packages/web/components/SparklineChart/SparklineChart.tsx +0 -40
- package/packages/web/components/SparklineChart/SparklineChart.types.ts +0 -6
- package/packages/web/components/SparklineChart/index.ts +0 -2
- package/packages/web/components/StatsMasonry/StatsMasonry.tsx +0 -95
- package/packages/web/components/StatsMasonry/index.ts +0 -1
- package/packages/web/components/StreakCard/StreakCard.constants.ts +0 -2
- package/packages/web/components/StreakCard/StreakCard.tsx +0 -55
- package/packages/web/components/StreakCard/StreakCard.types.ts +0 -4
- package/packages/web/components/StreakCard/index.ts +0 -2
- package/packages/web/components/TasksCounter/TasksCounter.tsx +0 -14
- package/packages/web/components/TasksCounter/TasksCounter.types.ts +0 -3
- package/packages/web/components/TasksCounter/index.ts +0 -2
- package/packages/web/components/TechStackBadges/TechStackBadges.tsx +0 -28
- package/packages/web/components/TechStackBadges/index.ts +0 -1
- package/packages/web/components/TerminalDock/DockToggleTab.tsx +0 -29
- package/packages/web/components/TerminalDock/TerminalDock.tsx +0 -386
- package/packages/web/components/TerminalDock/TerminalDockTab.tsx +0 -130
- package/packages/web/components/TerminalDock/TerminalTabBar.tsx +0 -142
- package/packages/web/components/TerminalDock/index.ts +0 -2
- package/packages/web/components/TerminalTabs/TerminalTab.tsx +0 -95
- package/packages/web/components/TerminalTabs/TerminalTabs.tsx +0 -211
- package/packages/web/components/TerminalTabs/index.ts +0 -1
- package/packages/web/components/VelocityBadge/VelocityBadge.tsx +0 -32
- package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +0 -3
- package/packages/web/components/VelocityBadge/index.ts +0 -2
- package/packages/web/components/VelocityCard/VelocityCard.tsx +0 -73
- package/packages/web/components/VelocityCard/VelocityCard.types.ts +0 -7
- package/packages/web/components/VelocityCard/index.ts +0 -2
- package/packages/web/components/WeeklyReports/PrintableReport.tsx +0 -259
- package/packages/web/components/WeeklyReports/ReportPreviewCard.tsx +0 -187
- package/packages/web/components/WeeklyReports/WeekCalendar.tsx +0 -288
- package/packages/web/components/WeeklyReports/WeeklyReports.tsx +0 -149
- package/packages/web/components/WeeklyReports/index.ts +0 -4
- package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +0 -25
- package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +0 -4
- package/packages/web/components/WeeklySparkline/index.ts +0 -2
- package/packages/web/components/charts/SessionsChart.tsx +0 -175
- package/packages/web/components/ui/alert-dialog.tsx +0 -157
- package/packages/web/components/ui/badge.tsx +0 -46
- package/packages/web/components/ui/button.tsx +0 -60
- package/packages/web/components/ui/card.tsx +0 -92
- package/packages/web/components/ui/chart.tsx +0 -385
- package/packages/web/components/ui/dialog.tsx +0 -143
- package/packages/web/components/ui/drawer.tsx +0 -135
- package/packages/web/components/ui/dropdown-menu.tsx +0 -257
- package/packages/web/components/ui/input.tsx +0 -21
- package/packages/web/components/ui/scroll-area.tsx +0 -58
- package/packages/web/components/ui/select.tsx +0 -187
- package/packages/web/components/ui/sheet.tsx +0 -139
- package/packages/web/components/ui/tabs.tsx +0 -66
- package/packages/web/components/ui/tooltip.tsx +0 -61
- package/packages/web/components.json +0 -22
- package/packages/web/context/GlobalTerminalContext.tsx +0 -538
- package/packages/web/context/TerminalContext.tsx +0 -45
- package/packages/web/context/TerminalTabsContext.tsx +0 -181
- package/packages/web/eslint.config.mjs +0 -18
- package/packages/web/hooks/useClaudeTerminal.ts +0 -425
- package/packages/web/hooks/useProjectStats.ts +0 -93
- package/packages/web/hooks/useProjects.ts +0 -73
- package/packages/web/lib/actions/projects.ts +0 -15
- package/packages/web/lib/commands.ts +0 -81
- package/packages/web/lib/format.ts +0 -23
- package/packages/web/lib/generate-week-report.ts +0 -285
- package/packages/web/lib/parse-prjct-files.ts +0 -1123
- package/packages/web/lib/project-colors.ts +0 -58
- package/packages/web/lib/projects.ts +0 -506
- package/packages/web/lib/pty.ts +0 -101
- package/packages/web/lib/query-config.ts +0 -44
- package/packages/web/lib/services/index.ts +0 -9
- package/packages/web/lib/services/projects.server.ts +0 -66
- package/packages/web/lib/services/stats.server.ts +0 -562
- package/packages/web/lib/unified-loader.ts +0 -396
- package/packages/web/lib/utils.ts +0 -6
- package/packages/web/next-env.d.ts +0 -6
- package/packages/web/next.config.ts +0 -7
- package/packages/web/package.json +0 -57
- package/packages/web/postcss.config.mjs +0 -7
- package/packages/web/public/file.svg +0 -1
- package/packages/web/public/globe.svg +0 -1
- package/packages/web/public/next.svg +0 -1
- package/packages/web/public/vercel.svg +0 -1
- package/packages/web/public/window.svg +0 -1
- package/packages/web/server.ts +0 -312
- package/packages/web/tsconfig.json +0 -34
- package/templates/commands/serve.md +0 -121
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useQuery } from '@tanstack/react-query'
|
|
4
|
-
import { useTheme } from 'next-themes'
|
|
5
|
-
import { Settings as SettingsIcon, CheckCircle, XCircle, Terminal, Sun, Moon, Monitor } from 'lucide-react'
|
|
6
|
-
import { Button } from '@/components/ui/button'
|
|
7
|
-
|
|
8
|
-
export default function Settings() {
|
|
9
|
-
const { theme, setTheme } = useTheme()
|
|
10
|
-
|
|
11
|
-
const { data: claudeStatus } = useQuery({
|
|
12
|
-
queryKey: ['claude-status'],
|
|
13
|
-
queryFn: async () => {
|
|
14
|
-
const res = await fetch('/api/claude/status')
|
|
15
|
-
const json = await res.json()
|
|
16
|
-
return json.data
|
|
17
|
-
}
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<div className="p-6 h-full overflow-auto">
|
|
22
|
-
<header className="mb-6">
|
|
23
|
-
<h1 className="text-2xl font-bold flex items-center gap-2">
|
|
24
|
-
<SettingsIcon className="w-6 h-6" />
|
|
25
|
-
Settings
|
|
26
|
-
</h1>
|
|
27
|
-
</header>
|
|
28
|
-
|
|
29
|
-
<div className="space-y-6 max-w-2xl">
|
|
30
|
-
{/* Appearance */}
|
|
31
|
-
<section className="bg-card border border-border rounded-lg p-6">
|
|
32
|
-
<h2 className="text-lg font-semibold mb-4 flex items-center gap-2">
|
|
33
|
-
<Sun className="w-5 h-5" />
|
|
34
|
-
Appearance
|
|
35
|
-
</h2>
|
|
36
|
-
|
|
37
|
-
<div className="space-y-4">
|
|
38
|
-
<div>
|
|
39
|
-
<p className="text-sm text-muted-foreground mb-3">
|
|
40
|
-
Choose how prjct looks to you. Select a single theme, or sync with your system settings.
|
|
41
|
-
</p>
|
|
42
|
-
<div className="flex gap-2">
|
|
43
|
-
<Button
|
|
44
|
-
variant={theme === 'light' ? 'default' : 'outline'}
|
|
45
|
-
size="sm"
|
|
46
|
-
onClick={() => setTheme('light')}
|
|
47
|
-
className="flex items-center gap-2"
|
|
48
|
-
>
|
|
49
|
-
<Sun className="w-4 h-4" />
|
|
50
|
-
Light
|
|
51
|
-
</Button>
|
|
52
|
-
<Button
|
|
53
|
-
variant={theme === 'dark' ? 'default' : 'outline'}
|
|
54
|
-
size="sm"
|
|
55
|
-
onClick={() => setTheme('dark')}
|
|
56
|
-
className="flex items-center gap-2"
|
|
57
|
-
>
|
|
58
|
-
<Moon className="w-4 h-4" />
|
|
59
|
-
Dark
|
|
60
|
-
</Button>
|
|
61
|
-
<Button
|
|
62
|
-
variant={theme === 'system' ? 'default' : 'outline'}
|
|
63
|
-
size="sm"
|
|
64
|
-
onClick={() => setTheme('system')}
|
|
65
|
-
className="flex items-center gap-2"
|
|
66
|
-
>
|
|
67
|
-
<Monitor className="w-4 h-4" />
|
|
68
|
-
System
|
|
69
|
-
</Button>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
</div>
|
|
73
|
-
</section>
|
|
74
|
-
|
|
75
|
-
{/* Claude Code Status */}
|
|
76
|
-
<section className="bg-card border border-border rounded-lg p-6">
|
|
77
|
-
<h2 className="text-lg font-semibold mb-4 flex items-center gap-2">
|
|
78
|
-
<Terminal className="w-5 h-5" />
|
|
79
|
-
Claude Code CLI
|
|
80
|
-
</h2>
|
|
81
|
-
|
|
82
|
-
<div className="flex items-center gap-3 mb-4">
|
|
83
|
-
{claudeStatus?.available ? (
|
|
84
|
-
<>
|
|
85
|
-
<CheckCircle className="w-5 h-5 text-green-500" />
|
|
86
|
-
<span className="text-green-500">Available</span>
|
|
87
|
-
</>
|
|
88
|
-
) : (
|
|
89
|
-
<>
|
|
90
|
-
<XCircle className="w-5 h-5 text-red-500" />
|
|
91
|
-
<span className="text-red-500">Not Found</span>
|
|
92
|
-
</>
|
|
93
|
-
)}
|
|
94
|
-
</div>
|
|
95
|
-
|
|
96
|
-
{claudeStatus?.version && (
|
|
97
|
-
<p className="text-sm text-muted-foreground mb-4">
|
|
98
|
-
Version: {claudeStatus.version}
|
|
99
|
-
</p>
|
|
100
|
-
)}
|
|
101
|
-
|
|
102
|
-
<div className="bg-muted/50 rounded-md p-4 text-sm">
|
|
103
|
-
<p className="font-medium mb-2">How it works:</p>
|
|
104
|
-
<ul className="list-disc list-inside space-y-1 text-muted-foreground">
|
|
105
|
-
<li>prjct uses Claude Code CLI via PTY (pseudo-terminal)</li>
|
|
106
|
-
<li>Uses your existing Claude subscription (no API costs)</li>
|
|
107
|
-
<li>Full Claude Code experience in your browser</li>
|
|
108
|
-
<li>All tools work: Read, Write, Bash, etc.</li>
|
|
109
|
-
</ul>
|
|
110
|
-
</div>
|
|
111
|
-
|
|
112
|
-
{!claudeStatus?.available && (
|
|
113
|
-
<div className="mt-4 p-4 bg-yellow-500/10 border border-yellow-500/20 rounded-md">
|
|
114
|
-
<p className="text-sm text-yellow-500">
|
|
115
|
-
Install Claude Code CLI from{' '}
|
|
116
|
-
<a
|
|
117
|
-
href="https://claude.ai/code"
|
|
118
|
-
target="_blank"
|
|
119
|
-
rel="noopener noreferrer"
|
|
120
|
-
className="underline"
|
|
121
|
-
>
|
|
122
|
-
claude.ai/code
|
|
123
|
-
</a>
|
|
124
|
-
</p>
|
|
125
|
-
</div>
|
|
126
|
-
)}
|
|
127
|
-
</section>
|
|
128
|
-
|
|
129
|
-
{/* About */}
|
|
130
|
-
<section className="bg-card border border-border rounded-lg p-6">
|
|
131
|
-
<h2 className="text-lg font-semibold mb-4">About prjct</h2>
|
|
132
|
-
|
|
133
|
-
<div className="space-y-2 text-sm text-muted-foreground">
|
|
134
|
-
<p>
|
|
135
|
-
<strong className="text-foreground">prjct</strong> is a developer momentum tool.
|
|
136
|
-
</p>
|
|
137
|
-
<p>
|
|
138
|
-
Track progress, ship features, stay focused. Built for Claude.
|
|
139
|
-
</p>
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
|
-
<div className="mt-4 pt-4 border-t border-border">
|
|
143
|
-
<p className="text-xs text-muted-foreground">
|
|
144
|
-
Version 0.1.0 • Made with prjct.app
|
|
145
|
-
</p>
|
|
146
|
-
</div>
|
|
147
|
-
</section>
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
)
|
|
151
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { Activity } from 'lucide-react'
|
|
4
|
-
import { BentoCard } from '@/components/BentoCard'
|
|
5
|
-
import { EmptyState } from '@/components/EmptyState'
|
|
6
|
-
import { DateGroup } from '@/components/DateGroup'
|
|
7
|
-
import { ExpandButton } from '@/components/ExpandButton'
|
|
8
|
-
import { useExpandable, useGroupedEvents } from './hooks'
|
|
9
|
-
import { TIMELINE_COLLAPSED_LIMIT, TIMELINE_EXPANDED_LIMIT } from './ActivityTimeline.constants'
|
|
10
|
-
import type { ActivityTimelineProps } from './ActivityTimeline.types'
|
|
11
|
-
|
|
12
|
-
export function ActivityTimeline({ timeline, className }: ActivityTimelineProps) {
|
|
13
|
-
const { expanded, toggle } = useExpandable(false)
|
|
14
|
-
const limit = expanded ? TIMELINE_EXPANDED_LIMIT : TIMELINE_COLLAPSED_LIMIT
|
|
15
|
-
const { grouped, hasMore } = useGroupedEvents(timeline, limit)
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<BentoCard
|
|
19
|
-
title="Recent Activity"
|
|
20
|
-
icon={Activity}
|
|
21
|
-
count={timeline.length > 0 ? `${timeline.length} events` : undefined}
|
|
22
|
-
className={className}
|
|
23
|
-
>
|
|
24
|
-
{timeline.length === 0 ? (
|
|
25
|
-
<EmptyState
|
|
26
|
-
icon={Activity}
|
|
27
|
-
title="No recent activity"
|
|
28
|
-
description="Activity will appear as you work"
|
|
29
|
-
compact
|
|
30
|
-
/>
|
|
31
|
-
) : (
|
|
32
|
-
<div className="space-y-3 sm:space-y-4">
|
|
33
|
-
{Array.from(grouped.entries()).map(([dateKey, events]) => (
|
|
34
|
-
<DateGroup key={dateKey} dateKey={dateKey} events={events} />
|
|
35
|
-
))}
|
|
36
|
-
|
|
37
|
-
{hasMore && (
|
|
38
|
-
<ExpandButton
|
|
39
|
-
expanded={expanded}
|
|
40
|
-
totalCount={timeline.length}
|
|
41
|
-
collapsedLimit={TIMELINE_COLLAPSED_LIMIT}
|
|
42
|
-
onToggle={toggle}
|
|
43
|
-
/>
|
|
44
|
-
)}
|
|
45
|
-
</div>
|
|
46
|
-
)}
|
|
47
|
-
</BentoCard>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useMemo } from 'react'
|
|
4
|
-
import type { TimelineEvent } from '../ActivityTimeline.types'
|
|
5
|
-
|
|
6
|
-
export function useGroupedEvents(events: TimelineEvent[], limit: number) {
|
|
7
|
-
return useMemo(() => {
|
|
8
|
-
const displayEvents = events.slice(0, limit)
|
|
9
|
-
const groups = new Map<string, TimelineEvent[]>()
|
|
10
|
-
|
|
11
|
-
displayEvents.forEach(event => {
|
|
12
|
-
if (!event.ts) return
|
|
13
|
-
const dateKey = event.ts.split('T')[0]
|
|
14
|
-
const existing = groups.get(dateKey) ?? []
|
|
15
|
-
groups.set(dateKey, [...existing, event])
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
grouped: groups,
|
|
20
|
-
hasMore: events.length > limit,
|
|
21
|
-
}
|
|
22
|
-
}, [events, limit])
|
|
23
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
import { EmptyState } from '@/components/EmptyState'
|
|
5
|
-
import { ExpandButton } from '@/components/ExpandButton'
|
|
6
|
-
import { Bot, Star, TrendingUp, Wrench } from 'lucide-react'
|
|
7
|
-
import { Badge } from '@/components/ui/badge'
|
|
8
|
-
import { cn } from '@/lib/utils'
|
|
9
|
-
import type { AgentsCardProps } from './AgentsCard.types'
|
|
10
|
-
|
|
11
|
-
const COLLAPSED_LIMIT = 12
|
|
12
|
-
|
|
13
|
-
export function AgentsCard({ agents, codeHref, className }: AgentsCardProps) {
|
|
14
|
-
const [expanded, setExpanded] = useState(false)
|
|
15
|
-
const displayAgents = expanded ? agents : agents.slice(0, COLLAPSED_LIMIT)
|
|
16
|
-
const hasMore = agents.length > COLLAPSED_LIMIT
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div className={cn(
|
|
20
|
-
'relative overflow-hidden rounded-xl border bg-card p-4',
|
|
21
|
-
className
|
|
22
|
-
)}>
|
|
23
|
-
<div className="flex items-center justify-between mb-3">
|
|
24
|
-
<div className="flex items-center gap-2">
|
|
25
|
-
<Bot className="h-4 w-4 text-muted-foreground" />
|
|
26
|
-
<span className="text-xs font-bold uppercase tracking-[0.15em] text-muted-foreground">
|
|
27
|
-
Agents
|
|
28
|
-
</span>
|
|
29
|
-
</div>
|
|
30
|
-
<span className="text-xs font-medium text-muted-foreground tabular-nums">
|
|
31
|
-
{agents.length} available
|
|
32
|
-
</span>
|
|
33
|
-
</div>
|
|
34
|
-
|
|
35
|
-
{agents.length === 0 ? (
|
|
36
|
-
<EmptyState
|
|
37
|
-
icon={Bot}
|
|
38
|
-
title="No agents"
|
|
39
|
-
description="Run /p:sync to generate"
|
|
40
|
-
command="/p:sync"
|
|
41
|
-
href={codeHref}
|
|
42
|
-
compact
|
|
43
|
-
/>
|
|
44
|
-
) : (
|
|
45
|
-
<div className="space-y-2">
|
|
46
|
-
{displayAgents.map((agent) => {
|
|
47
|
-
const hasPerformance = agent.successRate !== undefined
|
|
48
|
-
const isTopPerformer = hasPerformance && agent.successRate! >= 80
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<div
|
|
52
|
-
key={agent.name}
|
|
53
|
-
className="flex items-center justify-between gap-2 py-1.5 px-2 rounded-lg -mx-2 hover:bg-muted/50"
|
|
54
|
-
>
|
|
55
|
-
<div className="flex items-center gap-2 min-w-0">
|
|
56
|
-
{isTopPerformer ? (
|
|
57
|
-
<Star className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
|
58
|
-
) : (
|
|
59
|
-
<Wrench className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
|
60
|
-
)}
|
|
61
|
-
<span className="font-mono text-sm truncate">@{agent.name}</span>
|
|
62
|
-
</div>
|
|
63
|
-
<div className="flex items-center gap-2 shrink-0">
|
|
64
|
-
{hasPerformance && (
|
|
65
|
-
<span className="text-xs font-medium tabular-nums text-muted-foreground">
|
|
66
|
-
{agent.successRate}%
|
|
67
|
-
</span>
|
|
68
|
-
)}
|
|
69
|
-
{agent.improving && (
|
|
70
|
-
<TrendingUp className="h-3 w-3 text-muted-foreground" />
|
|
71
|
-
)}
|
|
72
|
-
{agent.tasksCompleted !== undefined && agent.tasksCompleted > 0 && (
|
|
73
|
-
<Badge variant="secondary" className="text-xs px-1.5 py-0 h-4">
|
|
74
|
-
{agent.tasksCompleted} tasks
|
|
75
|
-
</Badge>
|
|
76
|
-
)}
|
|
77
|
-
</div>
|
|
78
|
-
</div>
|
|
79
|
-
)
|
|
80
|
-
})}
|
|
81
|
-
{hasMore && (
|
|
82
|
-
<ExpandButton
|
|
83
|
-
expanded={expanded}
|
|
84
|
-
totalCount={agents.length}
|
|
85
|
-
collapsedLimit={COLLAPSED_LIMIT}
|
|
86
|
-
onToggle={() => setExpanded(!expanded)}
|
|
87
|
-
/>
|
|
88
|
-
)}
|
|
89
|
-
</div>
|
|
90
|
-
)}
|
|
91
|
-
</div>
|
|
92
|
-
)
|
|
93
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export interface Agent {
|
|
2
|
-
name: string
|
|
3
|
-
description?: string
|
|
4
|
-
successRate?: number
|
|
5
|
-
tasksCompleted?: number
|
|
6
|
-
improving?: boolean
|
|
7
|
-
bestFor?: string[]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface AgentsCardProps {
|
|
11
|
-
agents: Agent[]
|
|
12
|
-
codeHref?: string
|
|
13
|
-
className?: string
|
|
14
|
-
}
|
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import Link from 'next/link'
|
|
4
|
-
import { usePathname } from 'next/navigation'
|
|
5
|
-
import {
|
|
6
|
-
LayoutDashboard,
|
|
7
|
-
Settings,
|
|
8
|
-
HelpCircle,
|
|
9
|
-
Menu,
|
|
10
|
-
PanelLeft,
|
|
11
|
-
Terminal,
|
|
12
|
-
} from 'lucide-react'
|
|
13
|
-
import { useGlobalTerminal } from '@/context/GlobalTerminalContext'
|
|
14
|
-
import { Badge } from '@/components/ui/badge'
|
|
15
|
-
import { ProjectSelectorModal } from '@/components/ProjectSelectorModal'
|
|
16
|
-
import { Logo } from '@/components/Logo'
|
|
17
|
-
import { cn } from '@/lib/utils'
|
|
18
|
-
import { useState, useEffect } from 'react'
|
|
19
|
-
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
|
|
20
|
-
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
|
21
|
-
|
|
22
|
-
const navItems = [
|
|
23
|
-
{ href: '/', icon: LayoutDashboard, label: 'Dashboard' },
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
function SidebarContent({
|
|
27
|
-
onNavigate,
|
|
28
|
-
isCollapsed = false,
|
|
29
|
-
onToggleCollapse,
|
|
30
|
-
onTerminalClick,
|
|
31
|
-
sessionCount
|
|
32
|
-
}: {
|
|
33
|
-
onNavigate?: () => void
|
|
34
|
-
isCollapsed?: boolean
|
|
35
|
-
onToggleCollapse?: () => void
|
|
36
|
-
onTerminalClick?: () => void
|
|
37
|
-
sessionCount?: number
|
|
38
|
-
}) {
|
|
39
|
-
const pathname = usePathname()
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<>
|
|
43
|
-
{/* Header */}
|
|
44
|
-
<div className={cn(
|
|
45
|
-
"flex h-14 items-center border-b border-border",
|
|
46
|
-
isCollapsed ? "justify-center px-2" : "justify-between px-3"
|
|
47
|
-
)}>
|
|
48
|
-
{!isCollapsed && (
|
|
49
|
-
<Link href="/" onClick={onNavigate}>
|
|
50
|
-
<Logo size="xs" showText rounded />
|
|
51
|
-
</Link>
|
|
52
|
-
)}
|
|
53
|
-
{onToggleCollapse && (
|
|
54
|
-
<Tooltip>
|
|
55
|
-
<TooltipTrigger asChild>
|
|
56
|
-
<button
|
|
57
|
-
onClick={onToggleCollapse}
|
|
58
|
-
className="h-8 w-8 rounded-md flex items-center justify-center text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors"
|
|
59
|
-
aria-label={isCollapsed ? "Expand sidebar" : "Collapse sidebar"}
|
|
60
|
-
>
|
|
61
|
-
<PanelLeft className="h-4 w-4" />
|
|
62
|
-
</button>
|
|
63
|
-
</TooltipTrigger>
|
|
64
|
-
<TooltipContent side="right">
|
|
65
|
-
{isCollapsed ? "Expand" : "Collapse"}
|
|
66
|
-
</TooltipContent>
|
|
67
|
-
</Tooltip>
|
|
68
|
-
)}
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
{/* Nav */}
|
|
72
|
-
<nav className={cn("flex-1 overflow-y-auto py-4", isCollapsed ? "px-2" : "px-3")}>
|
|
73
|
-
<div className="space-y-1">
|
|
74
|
-
{navItems.map(({ href, icon: Icon, label }) => {
|
|
75
|
-
const isActive = pathname === href || (href !== '/' && pathname.startsWith(href))
|
|
76
|
-
const linkContent = (
|
|
77
|
-
<Link
|
|
78
|
-
key={href}
|
|
79
|
-
href={href}
|
|
80
|
-
onClick={onNavigate}
|
|
81
|
-
className={cn(
|
|
82
|
-
'flex items-center rounded-md transition-colors min-h-[44px]',
|
|
83
|
-
isCollapsed ? 'justify-center px-2' : 'gap-3 px-3',
|
|
84
|
-
'py-2.5',
|
|
85
|
-
isActive
|
|
86
|
-
? 'bg-accent text-accent-foreground'
|
|
87
|
-
: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
|
|
88
|
-
)}
|
|
89
|
-
>
|
|
90
|
-
<Icon className="h-5 w-5 shrink-0" />
|
|
91
|
-
{!isCollapsed && <span className="text-sm font-medium">{label}</span>}
|
|
92
|
-
</Link>
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
if (isCollapsed) {
|
|
96
|
-
return (
|
|
97
|
-
<Tooltip key={href}>
|
|
98
|
-
<TooltipTrigger asChild>{linkContent}</TooltipTrigger>
|
|
99
|
-
<TooltipContent side="right">{label}</TooltipContent>
|
|
100
|
-
</Tooltip>
|
|
101
|
-
)
|
|
102
|
-
}
|
|
103
|
-
return linkContent
|
|
104
|
-
})}
|
|
105
|
-
|
|
106
|
-
{/* Terminal Button */}
|
|
107
|
-
{onTerminalClick && (
|
|
108
|
-
(() => {
|
|
109
|
-
const terminalButton = (
|
|
110
|
-
<button
|
|
111
|
-
onClick={onTerminalClick}
|
|
112
|
-
className={cn(
|
|
113
|
-
'flex items-center rounded-md transition-colors min-h-[44px] w-full',
|
|
114
|
-
isCollapsed ? 'justify-center px-2' : 'gap-3 px-3',
|
|
115
|
-
'py-2.5',
|
|
116
|
-
'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
|
|
117
|
-
)}
|
|
118
|
-
>
|
|
119
|
-
<div className="relative">
|
|
120
|
-
<Terminal className="h-5 w-5 shrink-0" />
|
|
121
|
-
{sessionCount !== undefined && sessionCount > 0 && (
|
|
122
|
-
<Badge
|
|
123
|
-
className="absolute -top-2 -right-2 h-4 w-4 p-0 flex items-center justify-center text-[10px] bg-primary"
|
|
124
|
-
>
|
|
125
|
-
{sessionCount}
|
|
126
|
-
</Badge>
|
|
127
|
-
)}
|
|
128
|
-
</div>
|
|
129
|
-
{!isCollapsed && <span className="text-sm font-medium">Terminal</span>}
|
|
130
|
-
</button>
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
if (isCollapsed) {
|
|
134
|
-
return (
|
|
135
|
-
<Tooltip key="terminal">
|
|
136
|
-
<TooltipTrigger asChild>{terminalButton}</TooltipTrigger>
|
|
137
|
-
<TooltipContent side="right">Terminal</TooltipContent>
|
|
138
|
-
</Tooltip>
|
|
139
|
-
)
|
|
140
|
-
}
|
|
141
|
-
return terminalButton
|
|
142
|
-
})()
|
|
143
|
-
)}
|
|
144
|
-
</div>
|
|
145
|
-
</nav>
|
|
146
|
-
|
|
147
|
-
{/* Footer */}
|
|
148
|
-
<div className={cn("border-t border-border space-y-1", isCollapsed ? "p-2" : "p-3")}>
|
|
149
|
-
{[
|
|
150
|
-
{ href: '/settings', icon: Settings, label: 'Settings' },
|
|
151
|
-
{ href: '/help', icon: HelpCircle, label: 'Need help?' }
|
|
152
|
-
].map(({ href, icon: Icon, label }) => {
|
|
153
|
-
const isActive = pathname === href
|
|
154
|
-
const linkContent = (
|
|
155
|
-
<Link
|
|
156
|
-
key={href}
|
|
157
|
-
href={href}
|
|
158
|
-
onClick={onNavigate}
|
|
159
|
-
className={cn(
|
|
160
|
-
'flex items-center rounded-md transition-colors min-h-[44px]',
|
|
161
|
-
isCollapsed ? 'justify-center px-2' : 'gap-3 px-3',
|
|
162
|
-
'py-2.5',
|
|
163
|
-
isActive
|
|
164
|
-
? 'bg-accent text-accent-foreground'
|
|
165
|
-
: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
|
|
166
|
-
)}
|
|
167
|
-
>
|
|
168
|
-
<Icon className="h-5 w-5 shrink-0" />
|
|
169
|
-
{!isCollapsed && <span className="text-sm font-medium">{label}</span>}
|
|
170
|
-
</Link>
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
if (isCollapsed) {
|
|
174
|
-
return (
|
|
175
|
-
<Tooltip key={href}>
|
|
176
|
-
<TooltipTrigger asChild>{linkContent}</TooltipTrigger>
|
|
177
|
-
<TooltipContent side="right">{label}</TooltipContent>
|
|
178
|
-
</Tooltip>
|
|
179
|
-
)
|
|
180
|
-
}
|
|
181
|
-
return linkContent
|
|
182
|
-
})}
|
|
183
|
-
</div>
|
|
184
|
-
</>
|
|
185
|
-
)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const SIDEBAR_COLLAPSED_KEY = 'prjct-sidebar-collapsed'
|
|
189
|
-
|
|
190
|
-
export function AppSidebar() {
|
|
191
|
-
const [isOpen, setIsOpen] = useState(false)
|
|
192
|
-
const [isMobile, setIsMobile] = useState(false)
|
|
193
|
-
const [isCollapsed, setIsCollapsed] = useState(false)
|
|
194
|
-
const [showProjectSelector, setShowProjectSelector] = useState(false)
|
|
195
|
-
const pathname = usePathname()
|
|
196
|
-
|
|
197
|
-
// Terminal context
|
|
198
|
-
const {
|
|
199
|
-
toggleDock,
|
|
200
|
-
openDock,
|
|
201
|
-
getTotalSessionCount,
|
|
202
|
-
projectSessions,
|
|
203
|
-
createSessionForProject,
|
|
204
|
-
} = useGlobalTerminal()
|
|
205
|
-
|
|
206
|
-
const sessionCount = getTotalSessionCount()
|
|
207
|
-
|
|
208
|
-
// Handle terminal button click
|
|
209
|
-
const handleTerminalClick = () => {
|
|
210
|
-
// If we're on a project page, auto-detect project
|
|
211
|
-
const projectMatch = pathname?.match(/\/project\/([^/]+)/)
|
|
212
|
-
|
|
213
|
-
if (projectMatch) {
|
|
214
|
-
const projectId = projectMatch[1]
|
|
215
|
-
const existingProject = projectSessions.get(projectId)
|
|
216
|
-
|
|
217
|
-
if (existingProject) {
|
|
218
|
-
// Project already has sessions, just toggle dock
|
|
219
|
-
toggleDock()
|
|
220
|
-
} else {
|
|
221
|
-
// Need to show project selector to get project details
|
|
222
|
-
// For now, open dock (will be empty) - the user should create session from the dock
|
|
223
|
-
setShowProjectSelector(true)
|
|
224
|
-
}
|
|
225
|
-
} else if (sessionCount > 0) {
|
|
226
|
-
// Has sessions, toggle dock
|
|
227
|
-
toggleDock()
|
|
228
|
-
} else {
|
|
229
|
-
// No sessions and no project context - show project selector
|
|
230
|
-
setShowProjectSelector(true)
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Load collapsed state from localStorage on mount
|
|
235
|
-
useEffect(() => {
|
|
236
|
-
const stored = localStorage.getItem(SIDEBAR_COLLAPSED_KEY)
|
|
237
|
-
if (stored !== null) {
|
|
238
|
-
setIsCollapsed(stored === 'true')
|
|
239
|
-
}
|
|
240
|
-
}, [])
|
|
241
|
-
|
|
242
|
-
// Persist collapsed state to localStorage
|
|
243
|
-
const handleToggleCollapse = () => {
|
|
244
|
-
const newValue = !isCollapsed
|
|
245
|
-
setIsCollapsed(newValue)
|
|
246
|
-
localStorage.setItem(SIDEBAR_COLLAPSED_KEY, String(newValue))
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Detect mobile on mount and resize
|
|
250
|
-
useEffect(() => {
|
|
251
|
-
const checkMobile = () => {
|
|
252
|
-
setIsMobile(window.innerWidth < 768)
|
|
253
|
-
}
|
|
254
|
-
checkMobile()
|
|
255
|
-
window.addEventListener('resize', checkMobile)
|
|
256
|
-
return () => window.removeEventListener('resize', checkMobile)
|
|
257
|
-
}, [])
|
|
258
|
-
|
|
259
|
-
// Mobile: Sheet/Drawer
|
|
260
|
-
if (isMobile) {
|
|
261
|
-
return (
|
|
262
|
-
<Sheet open={isOpen} onOpenChange={setIsOpen}>
|
|
263
|
-
<SheetTrigger asChild>
|
|
264
|
-
<button
|
|
265
|
-
className="fixed top-3 left-3 z-50 h-10 w-10 rounded-lg bg-card border border-border flex items-center justify-center text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors shadow-sm"
|
|
266
|
-
aria-label="Open menu"
|
|
267
|
-
>
|
|
268
|
-
<Menu className="h-5 w-5" />
|
|
269
|
-
</button>
|
|
270
|
-
</SheetTrigger>
|
|
271
|
-
<SheetContent side="left" className="w-[280px] p-0 flex flex-col">
|
|
272
|
-
<SidebarContent
|
|
273
|
-
onNavigate={() => setIsOpen(false)}
|
|
274
|
-
onTerminalClick={handleTerminalClick}
|
|
275
|
-
sessionCount={sessionCount}
|
|
276
|
-
/>
|
|
277
|
-
</SheetContent>
|
|
278
|
-
</Sheet>
|
|
279
|
-
)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Desktop: Collapsible sidebar
|
|
283
|
-
return (
|
|
284
|
-
<>
|
|
285
|
-
<aside className={cn(
|
|
286
|
-
"hidden md:flex h-full flex-col border-r border-border bg-card transition-all duration-200",
|
|
287
|
-
isCollapsed ? "w-14" : "w-60"
|
|
288
|
-
)}>
|
|
289
|
-
<SidebarContent
|
|
290
|
-
isCollapsed={isCollapsed}
|
|
291
|
-
onToggleCollapse={handleToggleCollapse}
|
|
292
|
-
onTerminalClick={handleTerminalClick}
|
|
293
|
-
sessionCount={sessionCount}
|
|
294
|
-
/>
|
|
295
|
-
</aside>
|
|
296
|
-
|
|
297
|
-
{/* Project Selector Modal - will be implemented separately */}
|
|
298
|
-
{showProjectSelector && (
|
|
299
|
-
<ProjectSelectorModal
|
|
300
|
-
isOpen={showProjectSelector}
|
|
301
|
-
onClose={() => setShowProjectSelector(false)}
|
|
302
|
-
onSelectProject={(projectId, projectName, projectPath) => {
|
|
303
|
-
createSessionForProject(projectId, projectName, projectPath)
|
|
304
|
-
openDock()
|
|
305
|
-
setShowProjectSelector(false)
|
|
306
|
-
}}
|
|
307
|
-
/>
|
|
308
|
-
)}
|
|
309
|
-
</>
|
|
310
|
-
)
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// Mobile header spacer - use in pages that need top padding for the menu button
|
|
314
|
-
export function MobileHeaderSpacer() {
|
|
315
|
-
return <div className="h-16 md:h-0" />
|
|
316
|
-
}
|