From 8231fc126712630c0559e63aee029be04498df6c Mon Sep 17 00:00:00 2001 From: Cosmin Popovici Date: Sun, 2 Aug 2026 17:19:11 +0300 Subject: [PATCH 1/2] feat(dev-server): keep sidebar folder label on one line Long group paths now stay on a single line with native horizontal scroll (no visible scrollbar) instead of wrapping. A directive-driven mask fades the left/right edges only when the label overflows in that direction, signaling there's more to scroll. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/server/ui/App.vue | 25 ++++++++++++++++++++++++- src/server/ui/main.css | 15 +++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/server/ui/App.vue b/src/server/ui/App.vue index 9b633972..430ea51c 100644 --- a/src/server/ui/App.vue +++ b/src/server/ui/App.vue @@ -290,6 +290,27 @@ function toggleDarkMode() { darkMode.value = !darkMode.value } +const vFade = { + mounted(el: HTMLElement) { + const update = () => { + const max = el.scrollWidth - el.clientWidth + el.style.setProperty('--fade-l', el.scrollLeft > 1 ? 'transparent' : '#000') + el.style.setProperty('--fade-r', el.scrollLeft < max - 1 ? 'transparent' : '#000') + } + ;(el as any)._fade = update + el.addEventListener('scroll', update, { passive: true }) + window.addEventListener('resize', update) + requestAnimationFrame(update) + }, + updated(el: HTMLElement) { + requestAnimationFrame((el as any)._fade) + }, + unmounted(el: HTMLElement) { + el.removeEventListener('scroll', (el as any)._fade) + window.removeEventListener('resize', (el as any)._fade) + }, +} + onMounted(() => { document.addEventListener('keydown', onKeydown) window.addEventListener('blur', onWindowBlur) @@ -329,7 +350,9 @@ onUnmounted(() => { - {{ dir }} + + {{ dir }} + diff --git a/src/server/ui/main.css b/src/server/ui/main.css index 6c6bf144..52bbc500 100644 --- a/src/server/ui/main.css +++ b/src/server/ui/main.css @@ -152,3 +152,18 @@ -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22h6a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v6'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='M3 22V14l4 4 4-4v8'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22h6a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v6'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='M3 22V14l4 4 4-4v8'/%3E%3C/svg%3E"); } + +@utility scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; + &::-webkit-scrollbar { + display: none; + } +} + +@utility fade-scroll { + --fade-l: #000; + --fade-r: #000; + -webkit-mask-image: linear-gradient(to right, var(--fade-l) 0, #000 1.5rem, #000 calc(100% - 1.5rem), var(--fade-r) 100%); + mask-image: linear-gradient(to right, var(--fade-l) 0, #000 1.5rem, #000 calc(100% - 1.5rem), var(--fade-r) 100%); +} From e25871b79cc31b631d695aab80e4fcc700ee8041 Mon Sep 17 00:00:00 2001 From: Cosmin Popovici Date: Sun, 2 Aug 2026 17:25:32 +0300 Subject: [PATCH 2/2] fix(dev-server): recalc label fade on element resize Observe the label element with a ResizeObserver so the edge fades update when the sidebar resizes without a window resize event. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/server/ui/App.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/server/ui/App.vue b/src/server/ui/App.vue index 430ea51c..09d4563b 100644 --- a/src/server/ui/App.vue +++ b/src/server/ui/App.vue @@ -300,6 +300,9 @@ const vFade = { ;(el as any)._fade = update el.addEventListener('scroll', update, { passive: true }) window.addEventListener('resize', update) + const observer = new ResizeObserver(update) + observer.observe(el) + ;(el as any)._fadeObserver = observer requestAnimationFrame(update) }, updated(el: HTMLElement) { @@ -308,6 +311,7 @@ const vFade = { unmounted(el: HTMLElement) { el.removeEventListener('scroll', (el as any)._fade) window.removeEventListener('resize', (el as any)._fade) + ;(el as any)._fadeObserver?.disconnect() }, }