fix: icon-rail sidebar now shows per-item label tooltips instead of full flyout
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 <noreply@anthropic.com>
This commit is contained in:
parent
a4128788d6
commit
41f747a7b0
@ -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
|
## [1.12.0] — 2026-06-27
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
|
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
|
||||||
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
|
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
|
||||||
<link rel="stylesheet" href="/static/style.css?v=1.12.0">
|
<link rel="stylesheet" href="/static/style.css?v=1.12.1">
|
||||||
|
|
||||||
|
|
||||||
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
||||||
@ -336,7 +336,7 @@
|
|||||||
<script src="/static/vendor/wavesurfer-regions.min.js"></script>
|
<script src="/static/vendor/wavesurfer-regions.min.js"></script>
|
||||||
|
|
||||||
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
||||||
<script src="/static/loader.js?v=1.12.0"></script>
|
<script src="/static/loader.js?v=1.12.1"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -377,8 +377,40 @@
|
|||||||
try { localStorage.setItem('ttsvc_sidebar_collapsed', collapsed ? '1' : '0'); } catch (_) {}
|
try { localStorage.setItem('ttsvc_sidebar_collapsed', collapsed ? '1' : '0'); } catch (_) {}
|
||||||
var btn = document.getElementById('sidebar-collapse-btn');
|
var btn = document.getElementById('sidebar-collapse-btn');
|
||||||
if (btn) btn.title = collapsed ? 'Expand sidebar' : 'Collapse sidebar';
|
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
|
// Close drawer when a nav item is tapped on mobile
|
||||||
document.querySelectorAll('#sidebar .nav-item, #sidebar .nav-tree-item').forEach(function (el) {
|
document.querySelectorAll('#sidebar .nav-item, #sidebar .nav-tree-item').forEach(function (el) {
|
||||||
el.addEventListener('click', function () {
|
el.addEventListener('click', function () {
|
||||||
|
|||||||
@ -114,38 +114,41 @@ body {
|
|||||||
#sidebar { transition: width .18s ease; }
|
#sidebar { transition: width .18s ease; }
|
||||||
.sidebar-expand-btn { display: none; }
|
.sidebar-expand-btn { display: none; }
|
||||||
|
|
||||||
/* ── Collapsed = slim icon rail; hovering it flies the full menu out as an
|
/* ── Collapsed = slim 56 px icon rail; individual item labels appear as
|
||||||
overlay (icons always visible, titles + nested items appear on hover) ── */
|
floating tooltips via JS (#nav-rail-tooltip) — layout never shifts ── */
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
body.sidebar-collapsed #sidebar { width: 56px; overflow-x: hidden; }
|
body.sidebar-collapsed #sidebar { width: 56px; overflow-x: hidden; }
|
||||||
body.sidebar-collapsed #sidebar:hover {
|
/* Rail: hide all text/badges/chevrons, keep leading icons only */
|
||||||
width: var(--sidebar-width); overflow-x: hidden;
|
body.sidebar-collapsed #sidebar .nav-label,
|
||||||
position: absolute; top: 0; bottom: 0; left: 0; z-index: 60;
|
body.sidebar-collapsed #sidebar .nav-badge,
|
||||||
box-shadow: 6px 0 24px rgba(0,0,0,.22);
|
body.sidebar-collapsed #sidebar .ntc,
|
||||||
}
|
body.sidebar-collapsed #sidebar .nav-chevron,
|
||||||
/* Rail (not hovered): show only the leading icons, centered */
|
body.sidebar-collapsed #sidebar .nav-group-label,
|
||||||
body.sidebar-collapsed #sidebar:not(:hover) .nav-label,
|
body.sidebar-collapsed #sidebar .nav-group-head,
|
||||||
body.sidebar-collapsed #sidebar:not(:hover) .nav-badge,
|
body.sidebar-collapsed #sidebar .sidebar-brand-text { display: none; }
|
||||||
body.sidebar-collapsed #sidebar:not(:hover) .ntc,
|
body.sidebar-collapsed #sidebar .sidebar-brand { justify-content: center; padding-left: 0; padding-right: 0; }
|
||||||
body.sidebar-collapsed #sidebar:not(:hover) .nav-chevron,
|
body.sidebar-collapsed #sidebar .nav-item,
|
||||||
body.sidebar-collapsed #sidebar:not(:hover) .nav-group-label,
|
body.sidebar-collapsed #sidebar .nav-tree-item,
|
||||||
body.sidebar-collapsed #sidebar:not(:hover) .nav-group-head,
|
body.sidebar-collapsed #sidebar .nav-tree-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 {
|
|
||||||
padding-left: 18px; padding-right: 0; gap: 0; white-space: nowrap;
|
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 .nav-item .mdi,
|
||||||
body.sidebar-collapsed #sidebar:not(:hover) .nav-item .mdi,
|
body.sidebar-collapsed #sidebar .nav-tree-item .mdi,
|
||||||
body.sidebar-collapsed #sidebar:not(:hover) .nav-tree-item .mdi,
|
body.sidebar-collapsed #sidebar .nav-tree-head .mdi { font-size: 15px; }
|
||||||
body.sidebar-collapsed #sidebar:not(:hover) .nav-tree-head .mdi { font-size: 15px; }
|
body.sidebar-collapsed #sidebar .nav-tree .nav-tree-item,
|
||||||
/* nested tree-items: align their icon into the rail too */
|
body.sidebar-collapsed #sidebar .nav-tree .nav-tree-head.nav-subhead,
|
||||||
body.sidebar-collapsed #sidebar:not(:hover) .nav-tree .nav-tree-item,
|
body.sidebar-collapsed #sidebar .nav-tree .nav-tree .nav-tree-item { padding-left: 18px; }
|
||||||
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; }
|
/* 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) {
|
@media (max-width: 767px) {
|
||||||
.sidebar-collapse-btn, .sidebar-expand-btn { display: none !important; }
|
.sidebar-collapse-btn, .sidebar-expand-btn { display: none !important; }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user