From f2a33a9164792499bd4f69e0c83862080656ac37 Mon Sep 17 00:00:00 2001
From: th
Date: Wed, 15 Apr 2026 21:20:27 +0200
Subject: [PATCH] bucket-bar: hide scrollbar, soft edge fades, wheel-to-scroll
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The horizontal scrollbar on the bucket row was ugly and
inconsistent with the rest of the app's scrollbar-less panels. Hide
it, redirect vertical wheel over the bar to horizontal scroll, and
surface overflow with soft bg-coloured gradients on whichever side
has more content off-screen: right only while anchored at the
start, both in the middle, left only at the end.
Fade overlays live on #bucket-row (parent) as pseudo-elements with
pointer-events:none, rather than mask-image on the bar itself — a
mask would also clip super-bucket popovers that are intentionally
rendered inside #bucket-bar for the collab MutationObserver.
Co-Authored-By: Claude Opus 4.6 (1M context)
---
config.php | 2 +-
electron/package.json | 2 +-
public/css/style.css | 44 ++++++++++++++++++++++++++++++++++++
public/js/modules/buckets.js | 37 ++++++++++++++++++++++++++++++
4 files changed, 83 insertions(+), 2 deletions(-)
diff --git a/config.php b/config.php
index 616d4cb..febdef0 100644
--- a/config.php
+++ b/config.php
@@ -1,7 +1,7 @@
2;
+ const canRight = bar.scrollLeft + bar.clientWidth < bar.scrollWidth - 2;
+ barRow.classList.toggle('fade-left', canLeft && !canRight);
+ barRow.classList.toggle('fade-right', !canLeft && canRight);
+ barRow.classList.toggle('fade-both', canLeft && canRight);
+ // Right-side fade overlay is anchored to the parent's right edge;
+ // the actual bar ends before the toolbar toggles. Compute the
+ // distance so the gradient lines up with the bar's right edge.
+ const rowRect = barRow.getBoundingClientRect();
+ const barRect = bar.getBoundingClientRect();
+ const rightInset = Math.max(0, rowRect.right - barRect.right);
+ barRow.style.setProperty('--bucket-row-right-inset', rightInset + 'px');
+}
+if (bar) {
+ bar.addEventListener('wheel', (e) => {
+ if (e.deltaY === 0) return;
+ if (bar.scrollWidth <= bar.clientWidth) return;
+ e.preventDefault();
+ bar.scrollLeft += e.deltaY;
+ }, { passive: false });
+ bar.addEventListener('scroll', updateBucketBarFades, { passive: true });
+ window.addEventListener('resize', updateBucketBarFades);
+ new MutationObserver(updateBucketBarFades).observe(bar, { childList: true, subtree: false });
+ updateBucketBarFades();
+}
+
/** Switch the active bucket without going through the click path —
* used by the number-key hotkeys (and any other code that wants to
* activate a bucket programmatically without triggering the super-
|