Skip to content

Commit 6328fb9

Browse files
authored
improve-commits-reordering (#11411)
* feat(ui): add 1200ms delay to commit title tooltip to reduce flicker * fix: clipping dropzones and cropped drop lines * fix: prevrent overlay lines from overflow the stack-view container
1 parent afafbbe commit 6328fb9

File tree

4 files changed

+81
-26
lines changed

4 files changed

+81
-26
lines changed

apps/desktop/src/components/BranchCommitList.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@
221221
{@const hasRemoteCommits = upstreamOnlyCommits.length > 0}
222222
{@const hasCommits = localAndRemoteCommits.length > 0}
223223

224-
{@render commitReorderDz(stackingReorderDropzoneManager.top(branchName))}
224+
<!-- {@render commitReorderDz(stackingReorderDropzoneManager.top(branchName))} -->
225225

226226
{#if hasCommits || hasRemoteCommits}
227227
<div
@@ -264,6 +264,8 @@
264264
</UpstreamCommitsAction>
265265
{/if}
266266

267+
{@render commitReorderDz(stackingReorderDropzoneManager.top(branchName))}
268+
267269
{#each localAndRemoteCommits as commit, i (commit.id)}
268270
{@const first = i === 0}
269271
{@const last = i === localAndRemoteCommits.length - 1}
Lines changed: 75 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script lang="ts">
2+
import { portal } from '@gitbutler/ui/utils/portal';
23
import { pxToRem } from '@gitbutler/ui/utils/pxToRem';
34
45
interface Props {
@@ -9,64 +10,116 @@
910
}
1011
1112
const { hovered, activated, advertize, yOffsetPx = 0 }: Props = $props();
13+
14+
let containerElement = $state<HTMLDivElement>();
15+
let indicatorElement = $state<HTMLDivElement>();
16+
let indicatorRect = $state<{ top: number; left: number; width: number; height: number }>();
17+
let stackViewElement = $state<Element | null>(null);
18+
19+
function updatePosition() {
20+
if (!indicatorElement) return;
21+
22+
const rect = indicatorElement.getBoundingClientRect();
23+
const stackView = indicatorElement.closest('.stack-view');
24+
if (!stackView) return;
25+
26+
stackViewElement = stackView;
27+
28+
const stackRect = stackView.getBoundingClientRect();
29+
const scrollTop = stackView.scrollTop || 0;
30+
31+
// Calculate position relative to .stack-view container including scroll offset
32+
indicatorRect = {
33+
top: rect.top - stackRect.top + scrollTop,
34+
left: rect.left - stackRect.left,
35+
width: rect.width,
36+
height: rect.height
37+
};
38+
}
39+
40+
$effect(() => {
41+
if (containerElement && indicatorElement && activated) {
42+
updatePosition();
43+
}
44+
});
1245
</script>
1346

1447
<div
48+
bind:this={containerElement}
1549
class="dropzone-target container"
1650
class:activated
1751
class:advertize
1852
class:hovered
1953
style:--y-offset="{pxToRem(yOffsetPx)}rem"
2054
>
21-
<div class="indicator"></div>
55+
<div bind:this={indicatorElement} class="indicator-placeholder"></div>
2256
</div>
2357

58+
{#if activated && indicatorRect && stackViewElement}
59+
<div
60+
class="indicator-portal"
61+
class:hovered
62+
class:advertize
63+
use:portal={stackViewElement}
64+
style:top="{indicatorRect.top}px"
65+
style:left="{indicatorRect.left}px"
66+
style:width="{indicatorRect.width}px"
67+
style:height="{indicatorRect.height}px"
68+
>
69+
<div class="indicator"></div>
70+
</div>
71+
{/if}
72+
2473
<style lang="postcss">
2574
.container {
26-
--dropzone-overlap: calc(var(--dropzone-height) / 2);
75+
--dropzone-overlap: calc(var(--dropzone-height) / -2);
2776
--dropzone-height: 24px;
2877
2978
display: flex;
30-
31-
z-index: var(--z-floating);
32-
79+
z-index: var(--z-modal);
3380
position: absolute;
3481
top: var(--y-offset);
3582
align-items: center;
3683
width: 100%;
37-
3884
height: var(--dropzone-height);
39-
margin-top: calc(var(--dropzone-overlap) * -1);
40-
transition: background-color 0.3s ease-in-out;
41-
42-
/* It is very important that all children are pointer-events: none */
43-
/* https://stackoverflow.com/questions/7110353/html5-dragleave-fired-when-hovering-a-child-element */
44-
& * {
45-
pointer-events: none;
46-
}
85+
margin-top: var(--dropzone-overlap);
86+
/* For debugging */
87+
/* background-color: rgba(238, 130, 238, 0.319); */
4788
4889
&:not(.activated) {
4990
display: none;
5091
}
5192
52-
&.hovered {
53-
& .indicator {
54-
background-color: var(--clr-theme-pop-element);
55-
}
93+
& > * {
94+
pointer-events: none; /* Block all nested elements */
5695
}
96+
}
97+
98+
.indicator-placeholder {
99+
width: 100%;
100+
height: 3px;
101+
margin-top: 1px;
102+
background-color: transparent;
103+
}
104+
105+
.indicator-portal {
106+
display: flex;
107+
z-index: var(--z-blocker);
108+
position: absolute;
109+
align-items: center;
110+
pointer-events: none;
57111
58-
&:not(.hovered).advertize {
112+
&.hovered {
59113
& .indicator {
60-
background-color: var(--clr-theme-pop-soft-hover);
114+
background-color: var(--clr-theme-pop-element);
61115
}
62116
}
63117
}
64118
65119
.indicator {
66120
width: 100%;
67121
height: 3px;
68-
margin-top: 1px;
69122
background-color: transparent;
70-
transition: opacity 0.1s;
123+
transition: background-color var(--transition-fast);
71124
}
72125
</style>

apps/desktop/src/components/CommitTitle.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
}
2222
</script>
2323

24-
<Tooltip text={getTitle()}>
24+
<Tooltip text={getTitle()} delay={1200}>
2525
<h3
2626
data-testid={TestId.CommitDrawerTitle}
2727
class="{className} commit-title"

packages/ui/src/lib/utils/portal.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
export function portal(node: HTMLElement, to: string) {
2-
const target = document.querySelector(to);
1+
export function portal(node: HTMLElement, to: string | Element) {
2+
const target = typeof to === 'string' ? document.querySelector(to) : to;
33
if (target) {
44
target.appendChild(node);
55
}

0 commit comments

Comments
 (0)