Skip to content

Commit 0436333

Browse files
committed
refactor: ui improvements, add project info, and update color theme
UI responsive improvements: - Remove global button/overflow:hidden for natural scrolling - Replace fixed 400px right panel with clamp(280px, 32vw, 460px) - Remove SelectedFilesPanel key prop to prevent remounting jank - Add overscroll-behavior: contain to all scroll containers - Remove FileTreeView double border and nested overflow - Remove arrow between branches, add :active row feedback - Move filter checkbox inline with action buttons - Add height-based media query for short windows - Fix search input box-sizing New features: - Add project path and folder name in diff control bar - Show "calculating..." in Total Tokens when busy Color theme improvements: - Update btn-primary to use subtle color mix for light/dark modes - Update tab active indicator with softer color blend - Update tab badge with subtle background and border - Update token progress fill colors to be less saturated - All colors now adapt properly to light and dark themes
1 parent 7708d0e commit 0436333

7 files changed

Lines changed: 128 additions & 84 deletions

File tree

apps/desktop/src/App.css

Lines changed: 87 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,15 @@
3939
.btn:hover { background: color-mix(in oklab, currentColor 10%, transparent); }
4040
.btn:active { transform: translateY(1px); }
4141
.btn:disabled { opacity:.55; cursor:not-allowed; }
42-
.btn-primary { --_bg: var(--primary); --_fg: var(--primary-contrast); --_bd: color-mix(in oklab, var(--primary) 85%, black); }
42+
.btn-primary {
43+
--_bg: color-mix(in oklab, var(--primary) 15%, var(--surface-2));
44+
--_fg: color-mix(in oklab, var(--primary) 90%, currentColor);
45+
--_bd: color-mix(in oklab, var(--primary) 40%, transparent);
46+
font-weight: 500;
47+
}
48+
.btn-primary:hover {
49+
--_bg: color-mix(in oklab, var(--primary) 25%, var(--surface-2));
50+
}
4351
.btn-ghost { --_bg: transparent; --_bd: var(--border-col); }
4452
.btn-icon { padding: var(--space-2); width:36px; height:36px; }
4553

@@ -128,8 +136,8 @@
128136
grid-template-rows: auto auto 1fr;
129137
grid-template-columns: 1fr;
130138
height: 100vh;
131-
width: 100vw;
132-
overflow: hidden;
139+
width: 100%;
140+
min-height: 0;
133141
}
134142

135143
.gc-header {
@@ -176,44 +184,56 @@
176184
overflow: hidden;
177185
}
178186

179-
.diff-bar-arrow {
180-
font-size: 1.25rem;
181-
color: var(--border-col);
182-
padding: 0 var(--space-2);
187+
.diff-bar-project-info {
188+
display: flex;
189+
align-items: center;
190+
gap: var(--space-2);
191+
padding: var(--space-2) var(--space-3);
192+
background: color-mix(in oklab, var(--surface-1) 50%, transparent);
193+
border-radius: var(--radius-sm);
194+
font-size: var(--text-sm);
195+
color: inherit;
196+
opacity: 0.8;
197+
}
198+
199+
.diff-bar-project-name {
200+
font-weight: 500;
201+
max-width: 200px;
202+
overflow: hidden;
203+
text-overflow: ellipsis;
204+
white-space: nowrap;
183205
}
184206

185207
.gc-main-content {
186208
display: grid;
187-
grid-template-columns: 1fr 400px;
209+
grid-template-columns: minmax(320px, 1fr) clamp(280px, 32vw, 460px);
188210
gap: var(--space-4);
189211
padding: var(--space-4);
190-
overflow: hidden;
191212
min-height: 0;
192213
}
193214

194215
.gc-left-panel {
195216
display: flex;
196217
flex-direction: column;
197-
overflow: hidden;
198218
border: 1px solid var(--border-col);
199219
border-radius: var(--radius-lg);
200220
background: var(--surface-1);
201221
min-height: 0;
222+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
202223
}
203224

204225
.gc-right-panel {
205226
display: flex;
206227
flex-direction: column;
207-
overflow: hidden;
208228
border: 1px solid var(--border-col);
209229
border-radius: var(--radius-lg);
210230
background: var(--surface-1);
211231
min-height: 0;
232+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
212233
}
213234

214235
.gc-content {
215-
flex: 1;
216-
overflow: hidden;
236+
flex: 1 1 auto;
217237
display: flex;
218238
flex-direction: column;
219239
min-height: 0;
@@ -226,6 +246,26 @@
226246
}
227247
}
228248

249+
@media (max-width: 900px) {
250+
.gc-main-content {
251+
padding: var(--space-3);
252+
gap: var(--space-3);
253+
}
254+
}
255+
256+
/* Height-based media query for short desktop windows */
257+
@media (max-height: 700px) {
258+
.gc-header {
259+
padding: var(--space-2) var(--space-4);
260+
}
261+
.gc-diff-bar {
262+
padding: var(--space-2) var(--space-4);
263+
}
264+
.left-panel-controls {
265+
padding: var(--space-3);
266+
}
267+
}
268+
229269
.gc-button {
230270
display: inline-flex;
231271
align-items: center;
@@ -306,6 +346,8 @@
306346
flex-direction: column;
307347
gap: var(--space-1);
308348
overflow-y: auto;
349+
min-height: 0;
350+
overscroll-behavior: contain;
309351
}
310352

311353
.selected-file-row {
@@ -744,8 +786,16 @@ button {
744786
}
745787

746788
/* Rows & hovers */
747-
.tree-row, .selected-file-row { border-radius: var(--radius-sm); }
748-
.tree-row:hover, .selected-file-row:hover { background: color-mix(in oklab, currentColor 8%, transparent); }
789+
.tree-row, .selected-file-row {
790+
border-radius: var(--radius-sm);
791+
transition: background 0.1s ease, transform 0.05s ease;
792+
}
793+
.tree-row:hover, .selected-file-row:hover {
794+
background: color-mix(in oklab, currentColor 8%, transparent);
795+
}
796+
.tree-row:active, .selected-file-row:active {
797+
transform: translateY(1px);
798+
}
749799

750800
/* Status bar */
751801
.status-bar {
@@ -983,32 +1033,36 @@ button {
9831033
position: sticky;
9841034
top: 0;
9851035
z-index: 10;
986-
background: var(--surface-1);
987-
padding: var(--space-4);
1036+
background: color-mix(in oklab, var(--surface-1) 95%, transparent);
1037+
backdrop-filter: blur(8px);
1038+
padding: var(--space-3);
9881039
border-bottom: 1px solid var(--border-col);
9891040
display: flex;
9901041
flex-direction: column;
991-
gap: var(--space-3);
1042+
gap: var(--space-2);
9921043
}
9931044

994-
.tree-action-buttons {
1045+
.tree-controls-row {
9951046
display: flex;
1047+
align-items: center;
1048+
justify-content: space-between;
9961049
gap: var(--space-2);
9971050
flex-wrap: wrap;
9981051
}
9991052

1000-
.tree-filter-controls {
1053+
.tree-action-buttons {
10011054
display: flex;
1002-
align-items: center;
1055+
gap: var(--space-1);
10031056
}
10041057

10051058
.tree-filter-checkbox {
10061059
display: flex;
10071060
align-items: center;
10081061
gap: var(--space-2);
1009-
font-size: 13px;
1062+
font-size: 12px;
10101063
cursor: pointer;
10111064
user-select: none;
1065+
white-space: nowrap;
10121066
}
10131067

10141068
.tree-filter-checkbox input[type="checkbox"] {
@@ -1017,13 +1071,13 @@ button {
10171071

10181072
.tree-search-input {
10191073
position: relative;
1020-
width: 100%;
10211074
}
10221075

10231076
.tree-search-input input {
10241077
width: 100%;
10251078
font-size: 13px;
10261079
padding-right: var(--space-8);
1080+
box-sizing: border-box;
10271081
}
10281082

10291083
/* Search clear button */
@@ -1058,8 +1112,9 @@ button {
10581112
.left-panel-tree-container {
10591113
flex: 1;
10601114
overflow: auto;
1061-
padding: var(--space-2);
1115+
padding: var(--space-3);
10621116
min-height: 0;
1117+
overscroll-behavior: contain;
10631118
}
10641119

10651120
/* Enhanced FileTreeView styling removed to restore original tree design */
@@ -1106,7 +1161,8 @@ button {
11061161

11071162
.tab-nav-item.active {
11081163
opacity: 1;
1109-
border-bottom-color: var(--primary);
1164+
border-bottom-color: color-mix(in oklab, var(--primary) 80%, currentColor);
1165+
color: color-mix(in oklab, var(--primary) 70%, currentColor);
11101166
}
11111167

11121168
.tab-badge {
@@ -1117,16 +1173,18 @@ button {
11171173
height: 20px;
11181174
padding: 0 var(--space-2);
11191175
border-radius: 10px;
1120-
background: var(--primary);
1121-
color: var(--primary-contrast);
1176+
background: color-mix(in oklab, var(--primary) 20%, var(--surface-2));
1177+
color: color-mix(in oklab, var(--primary) 80%, currentColor);
11221178
font-size: 11px;
11231179
font-weight: 600;
1180+
border: 1px solid color-mix(in oklab, var(--primary) 30%, transparent);
11241181
}
11251182

11261183
.tab-content {
11271184
flex: 1;
11281185
overflow: auto;
11291186
min-height: 0;
1187+
overscroll-behavior: contain;
11301188
}
11311189

11321190
/* Selected files container */
@@ -1241,13 +1299,13 @@ button {
12411299

12421300
.token-progress-fill {
12431301
height: 100%;
1244-
background: var(--primary);
1302+
background: color-mix(in oklab, var(--primary) 60%, var(--surface-2));
12451303
transition: width 0.3s ease;
12461304
border-radius: 2px;
12471305
}
12481306

12491307
.token-progress-fill.over-limit {
1250-
background: #ef4444;
1308+
background: color-mix(in oklab, #ef4444 70%, var(--surface-2));
12511309
}
12521310

12531311
.copy-button {

apps/desktop/src/App.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -523,22 +523,23 @@ function AppContent() {
523523
onFlip={flipBranches}
524524
onRefresh={refreshRepo}
525525
disabled={isLoading}
526+
projectName={currentDir ? currentDir.split('/').pop() || currentDir : undefined}
527+
projectPath={currentDir || undefined}
526528
/>
527529

528530
<div className="gc-main-content">
529531
{/* Left panel: File tree */}
530532
<div className="gc-left-panel">
531533
{/* Tree controls - sticky */}
532534
<div className="left-panel-controls">
533-
{/* File tree controls */}
534-
<div className="tree-action-buttons">
535-
<button onClick={expandAll} className="btn btn-ghost btn-icon" title="Expand All" disabled={!fileTree}><ChevronsDown size={14} /></button>
536-
<button onClick={collapseAll} className="btn btn-ghost btn-icon" title="Collapse All" disabled={!fileTree}><ChevronsUp size={14} /></button>
537-
<button onClick={() => selectAll(treeFilter)} className="btn btn-ghost btn-icon" title="Select All" disabled={!fileTree}><CheckSquare size={14} /></button>
538-
<button onClick={() => deselectAll(treeFilter)} className="btn btn-ghost btn-icon" title="Deselect All" disabled={!fileTree}><Square size={14} /></button>
539-
</div>
540-
541-
<div className="tree-filter-controls">
535+
{/* File tree controls and filter checkbox in one row */}
536+
<div className="tree-controls-row">
537+
<div className="tree-action-buttons">
538+
<button onClick={expandAll} className="btn btn-ghost btn-icon" title="Expand All" disabled={!fileTree}><ChevronsDown size={14} /></button>
539+
<button onClick={collapseAll} className="btn btn-ghost btn-icon" title="Collapse All" disabled={!fileTree}><ChevronsUp size={14} /></button>
540+
<button onClick={() => selectAll(treeFilter)} className="btn btn-ghost btn-icon" title="Select All" disabled={!fileTree}><CheckSquare size={14} /></button>
541+
<button onClick={() => deselectAll(treeFilter)} className="btn btn-ghost btn-icon" title="Deselect All" disabled={!fileTree}><Square size={14} /></button>
542+
</div>
542543
<label className="tree-filter-checkbox">
543544
<input type="checkbox" checked={showChangedOnly} onChange={(e) => setShowChangedOnly(e.target.checked)} />
544545
Filter changed files only
@@ -601,7 +602,6 @@ function AppContent() {
601602
{activeTab === 'files' ? (
602603
<div className="selected-files-container">
603604
<SelectedFilesPanel
604-
key={`sel-${selectedPaths.size}`}
605605
selectedPaths={selectedPaths}
606606
statusByPath={statusByPath}
607607
onUnselect={(path) => toggleSelect(path)}

apps/desktop/src/components/ContextFooter.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function ContextFooter({
2020
copyFlash,
2121
disabled = false,
2222
}: ContextFooterProps) {
23-
const { total: filesTokens } = useTokenCountsContext()
23+
const { total: filesTokens, busy } = useTokenCountsContext()
2424
const totalTokens = filesTokens + instructionsTokens + fileTreeTokens
2525
const percentage = limit > 0 ? Math.min((totalTokens / limit) * 100, 100) : 0
2626
const isOverLimit = totalTokens > limit
@@ -48,7 +48,11 @@ export function ContextFooter({
4848
<div className="token-row token-total">
4949
<span className="token-label">Total Tokens:</span>
5050
<span className={`token-value ${isOverLimit ? 'over-limit' : ''}`}>
51-
{totalTokens.toLocaleString()} / {limit.toLocaleString()}
51+
{busy ? (
52+
<span style={{ opacity: 0.7 }}>calculating...</span>
53+
) : (
54+
`${totalTokens.toLocaleString()} / ${limit.toLocaleString()}`
55+
)}
5256
</span>
5357
</div>
5458
</div>

apps/desktop/src/components/DiffControlBar.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,6 @@ describe('DiffControlBar', () => {
159159

160160
expect(container.querySelector('.gc-diff-bar')).toBeInTheDocument()
161161
expect(container.querySelector('.diff-bar-branch-selector')).toBeInTheDocument()
162-
expect(container.querySelector('.diff-bar-arrow')).toBeInTheDocument()
162+
// Arrow removed - swap button is sufficient visual indicator
163163
})
164164
})

apps/desktop/src/components/DiffControlBar.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ArrowLeftRight, RefreshCw } from 'lucide-react'
1+
import { ArrowLeftRight, RefreshCw, Folder } from 'lucide-react'
22

33
type DiffControlBarProps = {
44
branches: string[]
@@ -9,6 +9,8 @@ type DiffControlBarProps = {
99
onFlip: () => void
1010
onRefresh: () => void
1111
disabled?: boolean
12+
projectName?: string
13+
projectPath?: string
1214
}
1315

1416
export function DiffControlBar({
@@ -20,12 +22,22 @@ export function DiffControlBar({
2022
onFlip,
2123
onRefresh,
2224
disabled = false,
25+
projectName,
26+
projectPath,
2327
}: DiffControlBarProps) {
2428
const formatBranchLabel = (branch: string) =>
2529
branch === '__WORKDIR__' ? 'My Working Directory' : branch
2630

2731
return (
2832
<div className="gc-diff-bar">
33+
{projectName && (
34+
<div className="diff-bar-project-info">
35+
<Folder size={16} style={{ opacity: 0.6 }} />
36+
<span className="diff-bar-project-name" title={projectPath || projectName}>
37+
{projectName}
38+
</span>
39+
</div>
40+
)}
2941
<div className="diff-bar-branch-selector">
3042
<label htmlFor="base-branch-select" className="diff-bar-label">Base</label>
3143
<select
@@ -52,8 +64,6 @@ export function DiffControlBar({
5264
<ArrowLeftRight size={18} />
5365
</button>
5466

55-
<div className="diff-bar-arrow"></div>
56-
5767
<div className="diff-bar-branch-selector">
5868
<label htmlFor="compare-branch-select" className="diff-bar-label">Compare</label>
5969
<select

0 commit comments

Comments
 (0)