From 38f614efc0d4e81f1cb1e3bb970b988e21ec2916 Mon Sep 17 00:00:00 2001 From: eti Date: Mon, 7 Sep 2026 16:38:34 +0200 Subject: [PATCH] web/repo: make FileTree resizeable & add hit-area utility to app.css Signed-off-by: eti --- web/src/app.css | 157 ++++++++++++++++++ .../lib/components/repo/pulls/PullDiff.svelte | 49 +++++- 2 files changed, 202 insertions(+), 4 deletions(-) diff --git a/web/src/app.css b/web/src/app.css index 26066e999..7fa06f13d 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -290,6 +290,163 @@ html { } } +@utility hit-area { + position: relative; + + &::before { + content: ""; + position: absolute; + top: var(--hit-area-t, 0px); + right: var(--hit-area-r, 0px); + bottom: var(--hit-area-b, 0px); + left: var(--hit-area-l, 0px); + pointer-events: inherit; + } +} + +@utility hit-area-* { + position: relative; + --hit-area-t: --spacing(--value(number) * -1); + --hit-area-t: calc(--value([*]) * -1); + --hit-area-b: --spacing(--value(number) * -1); + --hit-area-b: calc(--value([*]) * -1); + --hit-area-l: --spacing(--value(number) * -1); + --hit-area-l: calc(--value([*]) * -1); + --hit-area-r: --spacing(--value(number) * -1); + --hit-area-r: calc(--value([*]) * -1); + + &::before { + content: ""; + position: absolute; + top: var(--hit-area-t, 0px); + right: var(--hit-area-r, 0px); + bottom: var(--hit-area-b, 0px); + left: var(--hit-area-l, 0px); + pointer-events: inherit; + } +} + +@utility hit-area-l-* { + position: relative; + --hit-area-l: --spacing(--value(number) * -1); + --hit-area-l: calc(--value([*]) * -1); + + &::before { + content: ""; + position: absolute; + top: var(--hit-area-t, 0px); + right: var(--hit-area-r, 0px); + bottom: var(--hit-area-b, 0px); + left: var(--hit-area-l, 0px); + pointer-events: inherit; + } +} + +@utility hit-area-r-* { + position: relative; + --hit-area-r: --spacing(--value(number) * -1); + --hit-area-r: calc(--value([*]) * -1); + + &::before { + content: ""; + position: absolute; + top: var(--hit-area-t, 0px); + right: var(--hit-area-r, 0px); + bottom: var(--hit-area-b, 0px); + left: var(--hit-area-l, 0px); + pointer-events: inherit; + } +} + +@utility hit-area-t-* { + position: relative; + --hit-area-t: --spacing(--value(number) * -1); + --hit-area-t: calc(--value([*]) * -1); + + &::before { + content: ""; + position: absolute; + top: var(--hit-area-t, 0px); + right: var(--hit-area-r, 0px); + bottom: var(--hit-area-b, 0px); + left: var(--hit-area-l, 0px); + pointer-events: inherit; + } +} + +@utility hit-area-b-* { + position: relative; + --hit-area-b: --spacing(--value(number) * -1); + --hit-area-b: calc(--value([*]) * -1); + + &::before { + content: ""; + position: absolute; + top: var(--hit-area-t, 0px); + right: var(--hit-area-r, 0px); + bottom: var(--hit-area-b, 0px); + left: var(--hit-area-l, 0px); + pointer-events: inherit; + } +} + +@utility hit-area-x-* { + position: relative; + --hit-area-l: --spacing(--value(number) * -1); + --hit-area-l: calc(--value([*]) * -1); + --hit-area-r: --spacing(--value(number) * -1); + --hit-area-r: calc(--value([*]) * -1); + + &::before { + content: ""; + position: absolute; + top: var(--hit-area-t, 0px); + right: var(--hit-area-r, 0px); + bottom: var(--hit-area-b, 0px); + left: var(--hit-area-l, 0px); + pointer-events: inherit; + } +} + +@utility hit-area-y-* { + position: relative; + --hit-area-t: --spacing(--value(number) * -1); + --hit-area-t: calc(--value([*]) * -1); + --hit-area-b: --spacing(--value(number) * -1); + --hit-area-b: calc(--value([*]) * -1); + + &::before { + content: ""; + position: absolute; + top: var(--hit-area-t, 0px); + right: var(--hit-area-r, 0px); + bottom: var(--hit-area-b, 0px); + left: var(--hit-area-l, 0px); + pointer-events: inherit; + } +} + +@utility hit-area-debug { + position: relative; + + &::before { + content: ""; + position: absolute; + top: var(--hit-area-t, 0px); + right: var(--hit-area-r, 0px); + bottom: var(--hit-area-b, 0px); + left: var(--hit-area-l, 0px); + pointer-events: inherit; + @apply border border-dashed border-blue-500; + @apply bg-blue-500/10; + } + + &:hover::before { + @apply border border-dashed border-green-500; + @apply bg-green-500/10; + } +} + /* debug only. */ @utility debug-border { --debug-hue: 0; diff --git a/web/src/lib/components/repo/pulls/PullDiff.svelte b/web/src/lib/components/repo/pulls/PullDiff.svelte index cf3190047..8e20b5b29 100644 --- a/web/src/lib/components/repo/pulls/PullDiff.svelte +++ b/web/src/lib/components/repo/pulls/PullDiff.svelte @@ -20,9 +20,9 @@ import type { PullDiff, PullDiffDeps } from "$lib/api/pullDiff"; import Dropdown from "$lib/components/ui/Dropdown.svelte"; import DropdownItem from "$lib/components/ui/DropdownItem.svelte"; - import Separator from "$lib/components/ui/Separator.svelte"; import repoPullsPulldiffSkeletonFixture from "$lib/bones/repo-pulls-pulldiff--skeleton-fixture.bones.json"; import Bones from "$lib/components/ui/Bones.svelte"; + import Separator from "$lib/components/ui/Separator.svelte"; interface Props { deps: PullDiffDeps; @@ -57,6 +57,33 @@ }: Props = $props(); let treeOpen = $state(true); + const TREE_WIDTH = 320; + const TREE_MIN_WIDTH = 200; + const TREE_MAX_WIDTH = 560; + let treeWidth = $state(TREE_WIDTH); + let resizing = $state(false); + const startResize = (event: PointerEvent) => { + const handle = event.currentTarget as HTMLElement; + const startX = event.clientX; + const startWidth = treeWidth; + handle.setPointerCapture(event.pointerId); + resizing = true; + const move = (moved: PointerEvent) => { + treeWidth = Math.min( + TREE_MAX_WIDTH, + Math.max(TREE_MIN_WIDTH, startWidth + moved.clientX - startX) + ); + }; + const stop = () => { + resizing = false; + handle.removeEventListener("pointermove", move); + handle.removeEventListener("pointerup", stop); + handle.removeEventListener("pointercancel", stop); + }; + handle.addEventListener("pointermove", move); + handle.addEventListener("pointerup", stop); + handle.addEventListener("pointercancel", stop); + }; let shell = $state(); let dock = $state(0); let diffScroll = $state(0); @@ -106,7 +133,7 @@ {#if loading && !diff} {:else} -
+
{#if treeOpen} -