From 41f747a7b04d8baaedf31a671406af1e692ba7a5 Mon Sep 17 00:00:00 2001 From: mARTin-B78 Date: Sat, 27 Jun 2026 16:00:56 +0200 Subject: [PATCH] fix: icon-rail sidebar now shows per-item label tooltips instead of full flyout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hovering the collapsed 56 px rail no longer expands the whole sidebar, which was pushing the main content left and right. Each nav item now shows a small floating tooltip (JS-positioned fixed div) next to its icon on hover — layout stays completely stable. Bumps to v1.12.1. Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 7 ++++++ static/index.html | 4 ++-- static/nav.js | 32 +++++++++++++++++++++++++ static/style.css | 59 +++++++++++++++++++++++++---------------------- 4 files changed, 72 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fe78da..9e7e327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi --- +## [1.12.1] — 2026-06-27 + +### Changed +- **Sidebar icon-rail**: hover no longer flies out the whole sidebar (which caused the main content to jump left/right). Individual item labels now appear as a small floating tooltip next to the hovered icon, keeping the rail at a fixed 56 px and the layout completely stable. + +--- + ## [1.12.0] — 2026-06-27 ### Added diff --git a/static/index.html b/static/index.html index 8dd8e55..73afba6 100644 --- a/static/index.html +++ b/static/index.html @@ -26,7 +26,7 @@ - + @@ -336,7 +336,7 @@ - + diff --git a/static/nav.js b/static/nav.js index 10fda14..2de13e6 100644 --- a/static/nav.js +++ b/static/nav.js @@ -377,8 +377,40 @@ try { localStorage.setItem('ttsvc_sidebar_collapsed', collapsed ? '1' : '0'); } catch (_) {} var btn = document.getElementById('sidebar-collapse-btn'); if (btn) btn.title = collapsed ? 'Expand sidebar' : 'Collapse sidebar'; + if (!collapsed) _railTip.style.display = 'none'; }; + // ── Icon-rail per-item label tooltip ──────────────────────────────────── + var _railTip = document.createElement('div'); + _railTip.id = 'nav-rail-tooltip'; + document.body.appendChild(_railTip); + + var _railTipActive = null; + var _sidebarEl = document.getElementById('sidebar'); + + _sidebarEl.addEventListener('mouseover', function (e) { + if (!document.body.classList.contains('sidebar-collapsed')) return; + var item = e.target.closest('.nav-item, .nav-tree-item, .nav-tree-head'); + if (!item || item === _railTipActive) return; + var label = item.querySelector('.nav-label'); + if (!label) return; + var text = label.textContent.trim(); + if (!text) return; + var r = item.getBoundingClientRect(); + _railTip.textContent = text; + _railTip.style.left = (r.right + 10) + 'px'; + _railTip.style.top = (r.top + r.height / 2) + 'px'; + _railTip.style.display = 'block'; + _railTipActive = item; + }); + + _sidebarEl.addEventListener('mouseout', function (e) { + if (!e.relatedTarget || !e.relatedTarget.closest('#sidebar')) { + _railTip.style.display = 'none'; + _railTipActive = null; + } + }); + // Close drawer when a nav item is tapped on mobile document.querySelectorAll('#sidebar .nav-item, #sidebar .nav-tree-item').forEach(function (el) { el.addEventListener('click', function () { diff --git a/static/style.css b/static/style.css index a2ce7ff..77268a4 100644 --- a/static/style.css +++ b/static/style.css @@ -114,38 +114,41 @@ body { #sidebar { transition: width .18s ease; } .sidebar-expand-btn { display: none; } -/* ── Collapsed = slim icon rail; hovering it flies the full menu out as an - overlay (icons always visible, titles + nested items appear on hover) ── */ +/* ── Collapsed = slim 56 px icon rail; individual item labels appear as + floating tooltips via JS (#nav-rail-tooltip) — layout never shifts ── */ @media (min-width: 768px) { body.sidebar-collapsed #sidebar { width: 56px; overflow-x: hidden; } - body.sidebar-collapsed #sidebar:hover { - width: var(--sidebar-width); overflow-x: hidden; - position: absolute; top: 0; bottom: 0; left: 0; z-index: 60; - box-shadow: 6px 0 24px rgba(0,0,0,.22); - } - /* Rail (not hovered): show only the leading icons, centered */ - body.sidebar-collapsed #sidebar:not(:hover) .nav-label, - body.sidebar-collapsed #sidebar:not(:hover) .nav-badge, - body.sidebar-collapsed #sidebar:not(:hover) .ntc, - body.sidebar-collapsed #sidebar:not(:hover) .nav-chevron, - body.sidebar-collapsed #sidebar:not(:hover) .nav-group-label, - body.sidebar-collapsed #sidebar:not(:hover) .nav-group-head, - body.sidebar-collapsed #sidebar:not(:hover) .sidebar-brand-text { display: none; } - body.sidebar-collapsed #sidebar:not(:hover) .sidebar-brand { justify-content: center; padding-left: 0; padding-right: 0; } - body.sidebar-collapsed #sidebar:not(:hover) .nav-item, - body.sidebar-collapsed #sidebar:not(:hover) .nav-tree-item, - body.sidebar-collapsed #sidebar:not(:hover) .nav-tree-head { + /* Rail: hide all text/badges/chevrons, keep leading icons only */ + body.sidebar-collapsed #sidebar .nav-label, + body.sidebar-collapsed #sidebar .nav-badge, + body.sidebar-collapsed #sidebar .ntc, + body.sidebar-collapsed #sidebar .nav-chevron, + body.sidebar-collapsed #sidebar .nav-group-label, + body.sidebar-collapsed #sidebar .nav-group-head, + body.sidebar-collapsed #sidebar .sidebar-brand-text { display: none; } + body.sidebar-collapsed #sidebar .sidebar-brand { justify-content: center; padding-left: 0; padding-right: 0; } + body.sidebar-collapsed #sidebar .nav-item, + body.sidebar-collapsed #sidebar .nav-tree-item, + body.sidebar-collapsed #sidebar .nav-tree-head { padding-left: 18px; padding-right: 0; gap: 0; white-space: nowrap; - font-size: 0; /* hide raw-text labels + counts, keep the icon */ + font-size: 0; } - /* restore the leading icon size (its text was zeroed above) */ - body.sidebar-collapsed #sidebar:not(:hover) .nav-item .mdi, - body.sidebar-collapsed #sidebar:not(:hover) .nav-tree-item .mdi, - body.sidebar-collapsed #sidebar:not(:hover) .nav-tree-head .mdi { font-size: 15px; } - /* nested tree-items: align their icon into the rail too */ - body.sidebar-collapsed #sidebar:not(:hover) .nav-tree .nav-tree-item, - body.sidebar-collapsed #sidebar:not(:hover) .nav-tree .nav-tree-head.nav-subhead, - body.sidebar-collapsed #sidebar:not(:hover) .nav-tree .nav-tree .nav-tree-item { padding-left: 18px; } + body.sidebar-collapsed #sidebar .nav-item .mdi, + body.sidebar-collapsed #sidebar .nav-tree-item .mdi, + body.sidebar-collapsed #sidebar .nav-tree-head .mdi { font-size: 15px; } + body.sidebar-collapsed #sidebar .nav-tree .nav-tree-item, + body.sidebar-collapsed #sidebar .nav-tree .nav-tree-head.nav-subhead, + body.sidebar-collapsed #sidebar .nav-tree .nav-tree .nav-tree-item { padding-left: 18px; } +} +/* Floating label tooltip for icon-rail items */ +#nav-rail-tooltip { + position: fixed; z-index: 200; + background: var(--surface); border: 1px solid var(--border); + border-radius: 6px; padding: 5px 11px; + font-size: 13px; font-weight: 500; color: var(--text); + white-space: nowrap; pointer-events: none; display: none; + box-shadow: 2px 4px 14px rgba(0,0,0,.18); + transform: translateY(-50%); } @media (max-width: 767px) { .sidebar-collapse-btn, .sidebar-expand-btn { display: none !important; }