|
336 | 336 | return sortTree(root.children); |
337 | 337 | } |
338 | 338 |
|
| 339 | + // All changed-file paths under a tree node (the node itself if it's a file). |
| 340 | + function collectFilePaths(node: FileTreeNode): string[] { |
| 341 | + return node.isFile ? [node.path] : node.children.flatMap(collectFilePaths); |
| 342 | + } |
| 343 | +
|
| 344 | + // A folder counts as selected when every changed file under it is selected. |
| 345 | + function isFolderSelected(node: FileTreeNode): boolean { |
| 346 | + const filesUnder = collectFilePaths(node); |
| 347 | + return filesUnder.length > 0 && filesUnder.every(p => selectedPatchFiles.has(p)); |
| 348 | + } |
| 349 | +
|
339 | 350 | let fileTree = $derived(buildFileTree(files)); |
340 | 351 |
|
341 | 352 | // Auto-expand all directories when files change |
|
780 | 791 | {:else} |
781 | 792 | <button |
782 | 793 | class="dir-item" |
| 794 | + class:selected={isFolderSelected(node)} |
783 | 795 | style="padding-left: {8 + depth * 16}px;" |
784 | | - onclick={() => toggleDir(node.path)} |
| 796 | + onclick={(e) => { |
| 797 | + if ((e.ctrlKey || e.metaKey) && commit) { |
| 798 | + // Add/remove every changed file under this folder. |
| 799 | + const filesUnder = collectFilePaths(node); |
| 800 | + const next = new Set(selectedPatchFiles); |
| 801 | + const allSelected = filesUnder.length > 0 && filesUnder.every(p => next.has(p)); |
| 802 | + if (allSelected) { |
| 803 | + for (const p of filesUnder) next.delete(p); |
| 804 | + if (selectedFile && filesUnder.includes(selectedFile)) { |
| 805 | + selectedFile = next.size > 0 ? [...next][next.size - 1] : null; |
| 806 | + } |
| 807 | + } else { |
| 808 | + for (const p of filesUnder) next.add(p); |
| 809 | + if (filesUnder.length > 0) selectedFile = filesUnder[filesUnder.length - 1]; |
| 810 | + } |
| 811 | + selectedPatchFiles = next; |
| 812 | + return; |
| 813 | + } |
| 814 | + toggleDir(node.path); |
| 815 | + }} |
785 | 816 | oncontextmenu={(e) => { |
786 | 817 | e.preventDefault(); |
787 | 818 | if (!commit) return; |
|
1229 | 1260 |
|
1230 | 1261 | .file-item:hover, .dir-item:hover { background: var(--bg-hover); } |
1231 | 1262 | .file-item.selected { background: var(--bg-selected); color: var(--text-selected); } |
| 1263 | + .dir-item.selected { background: var(--bg-selected); color: var(--text-selected); } |
1232 | 1264 |
|
1233 | 1265 | .dir-item { |
1234 | 1266 | color: var(--text-secondary); |
|
0 commit comments