Skip to content

Commit 2f17c08

Browse files
committed
refactor: replace DirectoryPicker card grid with vertical list layout (OPE-117)
Card grid was hard to scan with 25+ packages -- cards wrapped unpredictably, proportional sizing added visual noise. New layout: clean vertical list, one row per package. - Checkbox on left, package name, file count, function estimate - Selected rows highlighted with bg-primary/5 + bold name - Dividers between rows, hover highlight - Staggered fade-in animation preserved (30ms per row) - Removed maxFiles/proportional sizing logic (not needed) Same props, same behavior, much easier to scan.
1 parent 5535521 commit 2f17c08

1 file changed

Lines changed: 26 additions & 31 deletions

File tree

frontend/src/components/DirectoryPicker.tsx

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/**
22
* DirectoryPicker -- monorepo package selection before indexing.
33
*
4-
* Shows an interactive card grid where each package is a clickable card
5-
* sized proportionally to its file count. Users select which packages
6-
* to index instead of the entire repo.
4+
* Shows a clean vertical list where each package is a row with
5+
* checkbox, name, file count, and function estimate. Users select
6+
* which packages to index instead of the entire repo.
77
*/
88

99
import { useState, useMemo } from 'react'
@@ -34,11 +34,6 @@ export function DirectoryPicker({
3434
}: DirectoryPickerProps) {
3535
const [selected, setSelected] = useState<Set<string>>(new Set())
3636

37-
const maxFiles = useMemo(
38-
() => Math.max(...repoInfo.directories.map((d) => d.file_count), 1),
39-
[repoInfo.directories],
40-
)
41-
4237
const stats = useMemo(() => {
4338
const dirs = repoInfo.directories.filter((d) => selected.has(d.path))
4439
return {
@@ -106,28 +101,27 @@ export function DirectoryPicker({
106101
</div>
107102
</div>
108103

109-
<ScrollArea className="flex-1 min-h-0 px-6">
104+
<ScrollArea className="flex-1 min-h-0">
110105
<motion.div
111-
className="flex flex-wrap gap-2 pb-4"
106+
className="divide-y divide-border"
112107
initial="hidden"
113108
animate="visible"
114109
variants={{
115110
hidden: {},
116-
visible: { transition: { staggerChildren: 0.04 } },
111+
visible: { transition: { staggerChildren: 0.03 } },
117112
}}
118113
>
119114
{repoInfo.directories.map((dir) => (
120115
<motion.div
121116
key={dir.path}
122117
variants={{
123-
hidden: { opacity: 0, y: 8 },
124-
visible: { opacity: 1, y: 0 },
118+
hidden: { opacity: 0 },
119+
visible: { opacity: 1 },
125120
}}
126121
>
127-
<PackageCard
122+
<PackageRow
128123
dir={dir}
129124
isSelected={selected.has(dir.path)}
130-
maxFiles={maxFiles}
131125
onToggle={() => toggleDir(dir.path)}
132126
/>
133127
</motion.div>
@@ -198,37 +192,38 @@ function PickerHeader({
198192
}
199193

200194

201-
function PackageCard({
195+
function PackageRow({
202196
dir,
203197
isSelected,
204-
maxFiles,
205198
onToggle,
206199
}: {
207200
dir: DirectoryEntry
208201
isSelected: boolean
209-
maxFiles: number
210202
onToggle: () => void
211203
}) {
212-
// Scale card width: smallest = 120px, largest = 240px
213-
const scale = dir.file_count / maxFiles
214-
const minWidth = Math.round(120 + scale * 120)
215-
216204
return (
217205
<button
218206
onClick={onToggle}
219-
style={{ minWidth }}
220207
className={cn(
221-
'flex flex-col gap-1 rounded-lg border p-3 text-left transition-all duration-200 cursor-pointer hover:scale-[1.02]',
208+
'flex items-center gap-3 w-full px-6 py-2.5 text-left transition-colors',
222209
isSelected
223-
? 'border-primary bg-primary/5 shadow-sm shadow-primary/10'
224-
: 'border-border bg-card/50 opacity-60 hover:opacity-80 hover:border-muted-foreground/30 hover:shadow-sm',
210+
? 'bg-primary/5'
211+
: 'hover:bg-muted/50',
225212
)}
226213
>
227-
<span className="text-sm font-medium truncate">{dir.name}</span>
228-
<div className="flex items-center gap-2 text-xs text-muted-foreground">
229-
<span>{dir.file_count} files</span>
230-
<span>~{dir.estimated_functions.toLocaleString()} fn</span>
231-
</div>
214+
<Checkbox checked={isSelected} tabIndex={-1} className="pointer-events-none" />
215+
<span className={cn(
216+
'text-sm flex-1 truncate',
217+
isSelected ? 'text-foreground font-medium' : 'text-muted-foreground',
218+
)}>
219+
{dir.name}
220+
</span>
221+
<span className="text-xs text-muted-foreground tabular-nums w-20 text-right">
222+
{dir.file_count} files
223+
</span>
224+
<span className="text-xs text-muted-foreground tabular-nums w-24 text-right">
225+
~{dir.estimated_functions.toLocaleString()} fn
226+
</span>
232227
</button>
233228
)
234229
}

0 commit comments

Comments
 (0)