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" + > + + +