Sticky header with centered tabs, scroll-spy, and full-width layout

- Move tab bar into header (centered between title and toolbar)
- Make entire header sticky with border-bottom separator
- Remove container max-width for full-width layout
- Add scroll-spy: tree sidebar tracks visible section on scroll
- Remember scroll position per tab when switching
- Remove sticky section headers, use scroll-margin-top instead
- Update sticky offsets to use --sticky-top CSS variable

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 15:29:37 +03:00
parent 304c4703b9
commit 6349e91e0f
10 changed files with 108 additions and 24 deletions

View File

@@ -21,8 +21,12 @@ function _setHash(tab, subTab) {
let _suppressHashUpdate = false;
let _activeTab = null;
const _tabScrollPositions = {};
export function switchTab(name, { updateHash = true, skipLoad = false } = {}) {
if (_activeTab === name) return;
// Save scroll position of the tab we're leaving
if (_activeTab) _tabScrollPositions[_activeTab] = window.scrollY;
_activeTab = name;
document.querySelectorAll('.tab-btn').forEach(btn => {
@@ -33,6 +37,9 @@ export function switchTab(name, { updateHash = true, skipLoad = false } = {}) {
document.querySelectorAll('.tab-panel').forEach(panel => panel.classList.toggle('active', panel.id === `tab-${name}`));
localStorage.setItem('activeTab', name);
// Restore scroll position for this tab
requestAnimationFrame(() => window.scrollTo(0, _tabScrollPositions[name] || 0));
if (updateHash && !_suppressHashUpdate) {
const subTab = name === 'targets'
? (localStorage.getItem('activeTargetSubTab') || 'led')