From 0550f7c2d263881f15ccfc82b8aa858c7265c422 Mon Sep 17 00:00:00 2001 From: Manjunath Paparaju Date: Sat, 14 Nov 2026 16:12:59 -0800 Subject: [PATCH] Place the Data Layers group label outside the panel and soften the finder's focus The group label is drawn on the page just outside the panel's edge instead of over the rows; the panel clips what leaves it, so the label is teleported to the body and placed from the tick. The finder shows focus as a soft ring on the field's frame in place of the hard outline round the bare input. Co-authored-by: Sameh Khamis --- src/ui/styles/layer-finder.css | 13 ++++++++ src/ui/styles/layer-section-index.css | 38 +++++++++++++---------- src/ui/views/panels/LayerSectionIndex.vue | 22 +++++++++++-- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/ui/styles/layer-finder.css b/src/ui/styles/layer-finder.css index 865e6b9c4..32a09092f 100644 --- a/src/ui/styles/layer-finder.css +++ b/src/ui/styles/layer-finder.css @@ -111,6 +111,19 @@ outline: none; } +/* Focus shows on the field's frame, as a soft ring, in place of the hard + keyboard outline round the bare input. */ +.layer-finder__field input:focus, +.layer-finder__field input:focus-visible { + outline: none !important; + box-shadow: none; +} + +.layer-finder__field:focus-within { + border-color: rgba(54, 220, 255, 0.7); + box-shadow: 0 0 0 3px rgba(54, 220, 255, 0.1); +} + .layer-finder__chip { display: inline-flex; flex: none; diff --git a/src/ui/styles/layer-section-index.css b/src/ui/styles/layer-section-index.css index a2695e019..1046f153e 100644 --- a/src/ui/styles/layer-section-index.css +++ b/src/ui/styles/layer-section-index.css @@ -60,12 +60,11 @@ outline: none; } -/* The group's name, shown to the left (inside the panel) on hover or - focus. Hidden labels take no room, so nothing reaches past the panel. */ +/* The group's name, drawn on the page just outside the panel's edge while a + tick is pointed at or focused, so it covers none of the rows. */ .layer-section-index__label { - position: absolute; - top: 50%; - right: 14px; + position: fixed; + z-index: 30; padding: 0.25rem 0.5rem; color: rgba(236, 244, 248, 0.92); font-family: var(--font-mono); @@ -76,21 +75,26 @@ background: rgba(12, 12, 20, 0.88); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 6px; - display: none; - opacity: 0; - transform: translate(4px, -50%); + transform: translateY(-50%); pointer-events: none; - z-index: 3; - transition: - opacity 120ms ease, - transform 120ms ease; + animation: layer-section-index-label 120ms ease both; } -.layer-section-index__tick:hover .layer-section-index__label, -.layer-section-index__tick:focus-visible .layer-section-index__label { - display: block; - opacity: 1; - transform: translate(0, -50%); +@keyframes layer-section-index-label { + from { + opacity: 0; + translate: -4px 0; + } + to { + opacity: 1; + translate: 0 0; + } +} + +@media (prefers-reduced-motion: reduce) { + .layer-section-index__label { + animation: none; + } } body.mobile-shell .layer-section-index { diff --git a/src/ui/views/panels/LayerSectionIndex.vue b/src/ui/views/panels/LayerSectionIndex.vue index 5bf6e394d..79f5b6262 100644 --- a/src/ui/views/panels/LayerSectionIndex.vue +++ b/src/ui/views/panels/LayerSectionIndex.vue @@ -32,6 +32,17 @@ function syncCurrent() { if (scrolls && list.scrollTop + list.clientHeight >= list.scrollHeight - 2) index = sections.value.length - 1; current.value = Math.max(0, index); } +// The name of the tick being pointed at or focused. It is drawn on the page +// itself, just outside the panel's edge: the panel clips what leaves it, and a +// label inside would cover the rows. +const tip = ref(null); +function showTip(event, section) { + const box = event.currentTarget.getBoundingClientRect(); + tip.value = { label: section.label, left: `${Math.round(box.right + 10)}px`, top: `${Math.round(box.top + box.height / 2)}px` }; +} +const hideTip = () => { + tip.value = null; +}; function jump(i) { const h = headings()[i]; if (!h || !list) return; @@ -67,8 +78,13 @@ onBeforeUnmount(() => { :aria-label="t('Jump to {name}', { name: section.label })" :aria-current="section.i === current ? 'true' : undefined" @click="jump(section.i)" - > - - + @mouseenter="showTip($event, section)" + @mouseleave="hideTip" + @focus="showTip($event, section)" + @blur="hideTip" + > + + +