Skip to content

Commit 5987430

Browse files
authored
Tree view design update (#7914)
* `BranchHeader` fix: copy and css * file tree view redesign * worktree changes title: truncate header
1 parent 8f404e5 commit 5987430

22 files changed

+608
-304
lines changed

apps/desktop/src/components/v3/BranchHeader.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
<span class="text-12 text-body branch-header__empty-state">
115115
This is an empty branch. Click to see details.
116116
<br />
117-
Create or drag & drop commits here
117+
Create or drag & drop commits here.
118118
</span>
119119
{:else}
120120
{@render details?.()}
@@ -177,6 +177,7 @@
177177
178178
&.new-branch {
179179
border-bottom: none;
180+
border-radius: var(--radius-ml);
180181
}
181182
}
182183

apps/desktop/src/components/v3/ChangedFiles.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@
4545
<div class="changed-files">
4646
<ReduxResult result={changesResult.current}>
4747
{#snippet children(changes)}
48-
<div class="header text-13 text-bold">
48+
<div class="header">
4949
<div class="header-left">
50-
<span>{headerTitle}</span>
50+
<h4 class="text-14 text-semibold">{headerTitle}</h4>
5151
<Badge>{changes.length}</Badge>
5252
</div>
5353
<FileListMode bind:mode={listMode} persist="committed" />
@@ -75,7 +75,7 @@
7575
}
7676
7777
.header {
78-
padding: 14px 14px 16px 14px;
78+
padding: 10px 10px 10px 14px;
7979
display: flex;
8080
align-items: center;
8181
gap: 4px;

apps/desktop/src/components/v3/FileList.svelte

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
<!-- This is a V3 replacement for `BranchFileList.svelte` -->
22
<script lang="ts">
3-
import ScrollableContainer from '$components/ConfigurableScrollableContainer.svelte';
43
import LazyloadContainer from '$components/LazyloadContainer.svelte';
54
import FileListItemWrapper from '$components/v3/FileListItemWrapper.svelte';
6-
import FileTree from '$components/v3/FileTree.svelte';
5+
import FileTreeNode from '$components/v3/FileTreeNode.svelte';
76
import { abbreviateFolders, changesToFileTree } from '$lib/files/filetreeV3';
87
import { IdSelection } from '$lib/selection/idSelection.svelte';
98
import { selectFilesInList, updateSelection } from '$lib/selection/idSelectionUtils';
@@ -80,13 +79,15 @@
8079
);
8180
</script>
8281

83-
{#snippet fileWrapper(change: TreeChange, idx: number)}
82+
{#snippet fileWrapper(change: TreeChange, idx: number, depth: number = 0)}
8483
<FileListItemWrapper
8584
selectedFile={selectionId}
8685
{change}
8786
{projectId}
8887
{listActive}
8988
{listMode}
89+
{depth}
90+
isLast={idx === visibleFiles.length - 1}
9091
selected={idSelection.has(change.path, selectionId)}
9192
onclick={(e) => {
9293
stackState?.activeSelectionId.set(selectionId);
@@ -96,34 +97,31 @@
9697
{/snippet}
9798

9899
{#if visibleFiles.length > 0}
99-
<div class="file-list hide-native-scrollbar">
100-
<ScrollableContainer wide>
101-
<!-- Maximum amount for initial render is 100 files
102-
`minTriggerCount` set to 80 in order to start the loading a bit earlier. -->
103-
<LazyloadContainer
104-
minTriggerCount={80}
105-
ontrigger={() => {
106-
loadMore();
100+
<LazyloadContainer
101+
minTriggerCount={80}
102+
ontrigger={() => {
103+
loadMore();
104+
}}
105+
role="listbox"
106+
onkeydown={handleKeyDown}
107+
>
108+
{#if listMode === 'tree'}
109+
{@const node = abbreviateFolders(changesToFileTree(changes))}
110+
<FileTreeNode
111+
isRoot
112+
{stackId}
113+
{node}
114+
{showCheckboxes}
115+
{changes}
116+
{fileWrapper}
117+
onFolderClick={() => {
118+
console.warn('implement folder click to select all children');
107119
}}
108-
role="listbox"
109-
onkeydown={handleKeyDown}
110-
>
111-
{#if listMode === 'tree'}
112-
{@const node = abbreviateFolders(changesToFileTree(changes))}
113-
<FileTree {stackId} {changes} {node} expanded {showCheckboxes} {fileWrapper} />
114-
{:else}
115-
{#each visibleFiles as change, idx (change.path)}
116-
{@render fileWrapper(change, idx)}
117-
{/each}
118-
{/if}
119-
</LazyloadContainer>
120-
</ScrollableContainer>
121-
</div>
120+
/>
121+
{:else}
122+
{#each visibleFiles as change, idx (change.path)}
123+
{@render fileWrapper(change, idx)}
124+
{/each}
125+
{/if}
126+
</LazyloadContainer>
122127
{/if}
123-
124-
<style lang="postcss">
125-
.file-list {
126-
flex-grow: 1;
127-
overflow: hidden;
128-
}
129-
</style>

apps/desktop/src/components/v3/FileListItemWrapper.svelte

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
selected?: boolean;
2323
isHeader?: boolean;
2424
listActive?: boolean;
25+
isLast?: boolean;
2526
listMode: 'list' | 'tree';
2627
linesAdded?: number;
2728
linesRemoved?: number;
29+
depth?: number;
2830
onclick?: (e: MouseEvent) => void;
2931
onkeydown?: (e: KeyboardEvent) => void;
3032
}
@@ -36,9 +38,11 @@
3638
selected,
3739
isHeader,
3840
listActive,
41+
isLast,
3942
listMode,
4043
linesAdded,
4144
linesRemoved,
45+
depth,
4246
onclick,
4347
onkeydown
4448
}: Props = $props();
@@ -137,6 +141,8 @@
137141
checked={!!selection.current}
138142
{listActive}
139143
{indeterminate}
144+
{isLast}
145+
{depth}
140146
draggable={!isCommitting}
141147
{onkeydown}
142148
locked={false}
@@ -153,11 +159,5 @@
153159
<style lang="postcss">
154160
.filelistitem-wrapper {
155161
display: block;
156-
157-
&.sticky {
158-
position: sticky;
159-
top: -1px;
160-
z-index: 1;
161-
}
162162
}
163163
</style>

apps/desktop/src/components/v3/FileListMode.svelte

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,10 @@
2424
defaultIndex={$saved === 'list' ? 0 : 1}
2525
onselect={(id) => {
2626
// TODO: Refactor SegmentControl.
27-
$saved = id as any;
27+
$saved = id as Mode;
2828
}}
29+
size="small"
2930
>
30-
<Segment id="list">List</Segment>
31-
<Segment id="tree">Tree</Segment>
31+
<Segment id="list" icon="list-view" />
32+
<Segment id="tree" icon="tree-view" />
3233
</SegmentControl>
33-
34-
<style lang="postcss">
35-
</style>

apps/desktop/src/components/v3/FileTree.svelte

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script lang="ts">
2+
interface Props {
3+
indentLevel: number;
4+
}
5+
6+
const { indentLevel }: Props = $props();
7+
</script>
8+
9+
<div class="filetree-indent">
10+
<span>
11+
{indentLevel}
12+
</span>
13+
</div>

apps/desktop/src/components/v3/FileTreeNode.svelte

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,59 +11,67 @@
1111
isRoot?: boolean;
1212
showCheckboxes: boolean;
1313
changes: TreeChange[];
14-
fileWrapper: Snippet<[TreeChange, number]>;
14+
depth?: number;
15+
fileWrapper: Snippet<[TreeChange, number, number]>;
16+
onFolderClick: (e: MouseEvent) => void;
1517
};
1618
17-
let { stackId, node, isRoot = false, showCheckboxes, changes, fileWrapper }: Props = $props();
19+
let {
20+
stackId,
21+
node,
22+
isRoot = false,
23+
showCheckboxes,
24+
changes,
25+
depth = 0,
26+
fileWrapper,
27+
onFolderClick
28+
}: Props = $props();
29+
30+
// Local state to track whether the folder is expanded
31+
let isExpanded = $state(true);
32+
33+
// Handler for toggling the folder
34+
function handleToggle() {
35+
isExpanded = !isExpanded;
36+
}
1837
</script>
1938

2039
{#if isRoot}
2140
<!-- Node is a root and should only render children! -->
22-
<div class="text-13">
23-
{#each node.children as childNode}
24-
<Self {stackId} node={childNode} {showCheckboxes} {changes} {fileWrapper} />
25-
{/each}
26-
</div>
41+
{#each node.children as childNode}
42+
<Self
43+
{depth}
44+
{stackId}
45+
node={childNode}
46+
{showCheckboxes}
47+
{changes}
48+
{fileWrapper}
49+
{onFolderClick}
50+
/>
51+
{/each}
2752
{:else if node.kind === 'file'}
28-
{@render fileWrapper(node.change, node.index)}
53+
{@render fileWrapper(node.change, node.index, depth)}
2954
{:else}
30-
<TreeListFolder showCheckbox={showCheckboxes} {node} />
55+
<TreeListFolder
56+
{depth}
57+
{isExpanded}
58+
showCheckbox={showCheckboxes}
59+
{node}
60+
onclick={onFolderClick}
61+
ontoggle={handleToggle}
62+
/>
3163

32-
<div class="nested">
33-
<div class="line-wrapper">
34-
<div class="line"></div>
35-
</div>
36-
<div class="files-list">
37-
{#each node.children as childNode}
38-
<Self {stackId} node={childNode} {showCheckboxes} {changes} {fileWrapper} />
39-
{/each}
40-
</div>
41-
</div>
64+
{#if isExpanded}
65+
{#each node.children as childNode}
66+
<Self
67+
depth={depth + 1}
68+
{stackId}
69+
node={childNode}
70+
{showCheckboxes}
71+
{changes}
72+
{fileWrapper}
73+
{onFolderClick}
74+
/>
75+
{/each}
76+
{/if}
4277
{/if}
43-
44-
<style lang="postcss">
45-
.nested {
46-
display: flex;
47-
width: 100%;
48-
overflow: hidden;
49-
}
50-
.line-wrapper {
51-
position: relative;
52-
padding-left: 7px;
53-
padding-right: 7px;
54-
&:hover .line {
55-
background-color: var(--clr-scale-ntrl-60);
56-
}
57-
}
58-
.line {
59-
width: 1px;
60-
height: 100%;
61-
background-color: var(--clr-scale-ntrl-80);
62-
}
63-
.files-list {
64-
display: flex;
65-
flex-direction: column;
66-
overflow: hidden;
67-
width: 100%;
68-
}
69-
</style>

0 commit comments

Comments
 (0)