Skip to content

Commit 3888ff8

Browse files
committed
Bump version to 1.1.23 and refine dashboard UI
1 parent ba2bb96 commit 3888ff8

File tree

10 files changed

+432
-76
lines changed

10 files changed

+432
-76
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vbcdr",
3-
"version": "1.1.22",
3+
"version": "1.1.23",
44
"description": "Desktop vibe coding environment for Claude Code developers",
55
"author": {
66
"name": "jo vinkenroye",
Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import { useEffect } from 'react'
1+
import { useEffect, useState } from 'react'
22
import { Plus } from 'lucide-react'
33
import { useProjectStore } from '@/stores/project-store'
4-
import { useTerminalStore } from '@/stores/terminal-store'
54
import { useGitStore } from '@/stores/git-store'
65
import { ProjectCard } from '@/components/dashboard/ProjectCard'
6+
import { ProjectModal } from '@/components/dashboard/ProjectModal'
7+
import type { Project } from '@/models/types'
78

89
export function Dashboard(): React.ReactElement {
910
const projects = useProjectStore((s) => s.projects)
1011
const addProject = useProjectStore((s) => s.addProject)
11-
const lastActivityPerProject = useTerminalStore((s) => s.lastActivityPerProject)
1212
const loadGitData = useGitStore((s) => s.loadGitData)
13+
const [modalProject, setModalProject] = useState<Project | null>(null)
1314

14-
const sorted = [...projects].sort(
15-
(a, b) => (lastActivityPerProject[b.id] ?? 0) - (lastActivityPerProject[a.id] ?? 0)
16-
)
15+
const sorted = [...projects].sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }))
1716

1817
useEffect(() => {
1918
for (const project of projects) {
@@ -23,16 +22,6 @@ export function Dashboard(): React.ReactElement {
2322

2423
return (
2524
<div className="flex h-full flex-col bg-zinc-950">
26-
<div className="flex items-center justify-between border-b border-zinc-800 px-6 py-3">
27-
<h1 className="text-sm font-medium text-zinc-300">Dashboard</h1>
28-
<button
29-
onClick={addProject}
30-
className="flex items-center gap-1.5 rounded-md bg-zinc-800 px-3 py-1.5 text-xs font-medium text-zinc-300 transition-colors hover:bg-zinc-700 hover:text-zinc-200"
31-
>
32-
<Plus size={12} />
33-
Add Project
34-
</button>
35-
</div>
3625
<div className="flex-1 overflow-auto p-6">
3726
{projects.length === 0 ? (
3827
<div className="flex h-full flex-col items-center justify-center gap-3 text-zinc-600">
@@ -46,13 +35,21 @@ export function Dashboard(): React.ReactElement {
4635
</button>
4736
</div>
4837
) : (
49-
<div className="grid gap-2" style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(600px, 1fr))' }}>
38+
<div className="grid gap-2" style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))' }}>
5039
{sorted.map((project) => (
51-
<ProjectCard key={project.id} project={project} />
40+
<ProjectCard
41+
key={project.id}
42+
project={project}
43+
onOpenModal={() => setModalProject(project)}
44+
isModalOpen={modalProject?.id === project.id}
45+
/>
5246
))}
5347
</div>
5448
)}
5549
</div>
50+
{modalProject && (
51+
<ProjectModal project={modalProject} onClose={() => setModalProject(null)} />
52+
)}
5653
</div>
5754
)
5855
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { useEffect, useRef } from 'react'
2+
import { getTerminalInstance } from '@/components/terminal/TerminalInstance'
3+
4+
interface ModalTerminalProps {
5+
tabId: string
6+
}
7+
8+
export function ModalTerminal({ tabId }: ModalTerminalProps): React.ReactElement {
9+
const containerRef = useRef<HTMLDivElement>(null)
10+
11+
useEffect(() => {
12+
const container = containerRef.current
13+
if (!container) return
14+
15+
const entry = getTerminalInstance(tabId)
16+
if (!entry) return
17+
18+
const termEl = entry.terminal.element
19+
if (!termEl) return
20+
21+
const originalParent = termEl.parentElement
22+
23+
termEl.style.width = '100%'
24+
termEl.style.height = '100%'
25+
container.appendChild(termEl)
26+
27+
const viewport = termEl.querySelector('.xterm-viewport') as HTMLElement | null
28+
const prevOverflow = viewport?.style.overflowY ?? ''
29+
if (viewport) viewport.style.overflowY = ''
30+
31+
setTimeout(() => {
32+
entry.fitAddon.fit()
33+
entry.terminal.scrollToBottom()
34+
entry.terminal.focus()
35+
}, 50)
36+
37+
let resizeTimer: ReturnType<typeof setTimeout> | null = null
38+
const observer = new ResizeObserver(() => {
39+
if (resizeTimer) clearTimeout(resizeTimer)
40+
resizeTimer = setTimeout(() => {
41+
try {
42+
if (!container.contains(entry.terminal.element)) return
43+
const atBottom = entry.terminal.buffer.active.viewportY === entry.terminal.buffer.active.baseY
44+
entry.fitAddon.fit()
45+
if (atBottom) entry.terminal.scrollToBottom()
46+
} catch { /* may unmount during resize */ }
47+
}, 80)
48+
})
49+
observer.observe(container)
50+
51+
return () => {
52+
if (resizeTimer) clearTimeout(resizeTimer)
53+
observer.disconnect()
54+
if (viewport) viewport.style.overflowY = prevOverflow
55+
termEl.style.width = ''
56+
termEl.style.height = ''
57+
if (originalParent) {
58+
originalParent.appendChild(termEl)
59+
}
60+
setTimeout(() => {
61+
entry.fitAddon.fit()
62+
entry.terminal.refresh(0, entry.terminal.rows - 1)
63+
}, 50)
64+
}
65+
}, [tabId])
66+
67+
return <div ref={containerRef} className="h-full w-full overflow-hidden bg-zinc-950" />
68+
}

src/renderer/components/dashboard/ProjectCard.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useState } from 'react'
22
import { GitBranch as GitBranchIcon, FileText, Terminal, Zap } from 'lucide-react'
3-
import { useProjectStore } from '@/stores/project-store'
43
import { useTerminalStore } from '@/stores/terminal-store'
54
import { useGitStore } from '@/stores/git-store'
65
import { useEditorStore } from '@/stores/editor-store'
@@ -38,6 +37,8 @@ function sanitizeLine(raw: string): string {
3837

3938
interface ProjectCardProps {
4039
project: Project
40+
onOpenModal: () => void
41+
isModalOpen: boolean
4142
}
4243

4344
type ClaudeStatus = 'busy' | 'idle' | 'none'
@@ -57,8 +58,7 @@ function useLlmTabs(projectId: string): TerminalTab[] {
5758
return tabs.filter((t) => t.projectId === projectId && t.initialCommand)
5859
}
5960

60-
export function ProjectCard({ project }: ProjectCardProps): React.ReactElement {
61-
const setActiveProject = useProjectStore((s) => s.setActiveProject)
61+
export function ProjectCard({ project, onOpenModal, isModalOpen }: ProjectCardProps): React.ReactElement {
6262
const branches = useGitStore((s) => s.branchesPerProject[project.id] ?? EMPTY_BRANCHES)
6363
const outputBuffer = useTerminalStore((s) => s.outputBufferPerProject[project.id] ?? EMPTY_OUTPUT)
6464
const openFilesCount = useEditorStore((s) => s.statePerProject[project.id]?.openFiles.length ?? 0)
@@ -81,12 +81,10 @@ export function ProjectCard({ project }: ProjectCardProps): React.ReactElement {
8181
.filter((l) => l.length > 0)
8282
.slice(-12)
8383

84-
const navigate = (): void => setActiveProject(project.id)
85-
8684
return (
8785
<div
8886
className="group flex w-full min-w-0 cursor-pointer flex-col gap-2 overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900/50 p-3 text-left transition-all hover:bg-zinc-800/50"
89-
onClick={navigate}
87+
onClick={onOpenModal}
9088
>
9189
<div className="flex items-center justify-between gap-2">
9290
<div className="flex items-center gap-2 min-w-0">
@@ -119,7 +117,7 @@ export function ProjectCard({ project }: ProjectCardProps): React.ReactElement {
119117
</div>
120118
</div>
121119

122-
{hasTerminal && activeTab ? (
120+
{hasTerminal && activeTab && !isModalOpen ? (
123121
<div className="flex w-full min-w-0 flex-col gap-1">
124122
{llmTabs.length > 1 && (
125123
<div className="flex items-center gap-1">

0 commit comments

Comments
 (0)