|
1 | 1 | /** |
2 | 2 | * DirectoryPicker -- monorepo package selection before indexing. |
3 | 3 | * |
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. |
7 | 7 | */ |
8 | 8 |
|
9 | 9 | import { useState, useMemo } from 'react' |
@@ -34,11 +34,6 @@ export function DirectoryPicker({ |
34 | 34 | }: DirectoryPickerProps) { |
35 | 35 | const [selected, setSelected] = useState<Set<string>>(new Set()) |
36 | 36 |
|
37 | | - const maxFiles = useMemo( |
38 | | - () => Math.max(...repoInfo.directories.map((d) => d.file_count), 1), |
39 | | - [repoInfo.directories], |
40 | | - ) |
41 | | - |
42 | 37 | const stats = useMemo(() => { |
43 | 38 | const dirs = repoInfo.directories.filter((d) => selected.has(d.path)) |
44 | 39 | return { |
@@ -106,28 +101,27 @@ export function DirectoryPicker({ |
106 | 101 | </div> |
107 | 102 | </div> |
108 | 103 |
|
109 | | - <ScrollArea className="flex-1 min-h-0 px-6"> |
| 104 | + <ScrollArea className="flex-1 min-h-0"> |
110 | 105 | <motion.div |
111 | | - className="flex flex-wrap gap-2 pb-4" |
| 106 | + className="divide-y divide-border" |
112 | 107 | initial="hidden" |
113 | 108 | animate="visible" |
114 | 109 | variants={{ |
115 | 110 | hidden: {}, |
116 | | - visible: { transition: { staggerChildren: 0.04 } }, |
| 111 | + visible: { transition: { staggerChildren: 0.03 } }, |
117 | 112 | }} |
118 | 113 | > |
119 | 114 | {repoInfo.directories.map((dir) => ( |
120 | 115 | <motion.div |
121 | 116 | key={dir.path} |
122 | 117 | variants={{ |
123 | | - hidden: { opacity: 0, y: 8 }, |
124 | | - visible: { opacity: 1, y: 0 }, |
| 118 | + hidden: { opacity: 0 }, |
| 119 | + visible: { opacity: 1 }, |
125 | 120 | }} |
126 | 121 | > |
127 | | - <PackageCard |
| 122 | + <PackageRow |
128 | 123 | dir={dir} |
129 | 124 | isSelected={selected.has(dir.path)} |
130 | | - maxFiles={maxFiles} |
131 | 125 | onToggle={() => toggleDir(dir.path)} |
132 | 126 | /> |
133 | 127 | </motion.div> |
@@ -198,37 +192,38 @@ function PickerHeader({ |
198 | 192 | } |
199 | 193 |
|
200 | 194 |
|
201 | | -function PackageCard({ |
| 195 | +function PackageRow({ |
202 | 196 | dir, |
203 | 197 | isSelected, |
204 | | - maxFiles, |
205 | 198 | onToggle, |
206 | 199 | }: { |
207 | 200 | dir: DirectoryEntry |
208 | 201 | isSelected: boolean |
209 | | - maxFiles: number |
210 | 202 | onToggle: () => void |
211 | 203 | }) { |
212 | | - // Scale card width: smallest = 120px, largest = 240px |
213 | | - const scale = dir.file_count / maxFiles |
214 | | - const minWidth = Math.round(120 + scale * 120) |
215 | | - |
216 | 204 | return ( |
217 | 205 | <button |
218 | 206 | onClick={onToggle} |
219 | | - style={{ minWidth }} |
220 | 207 | 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', |
222 | 209 | 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', |
225 | 212 | )} |
226 | 213 | > |
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> |
232 | 227 | </button> |
233 | 228 | ) |
234 | 229 | } |
|
0 commit comments