Refactor toolbar buttons across various pages to unify styling
- Updated button classes for consistency in the playersoftware-page, playlist-page, resolution-page, schedule-page, settings-page, syncgroup-page, tag-page, task-page, template-page, transition-page, user-page, and usergroup-page. - Removed unnecessary text from button titles and ensured all buttons have the 'ots-toolbar-btn' class for uniformity. - Cleaned up the code by removing commented-out sections and ensuring proper indentation.
This commit is contained in:
@@ -109,8 +109,11 @@
|
||||
body.classList.toggle('ots-sidebar-collapsed', nowCollapsed);
|
||||
document.documentElement.classList.toggle('ots-sidebar-collapsed', nowCollapsed);
|
||||
localStorage.setItem(STORAGE_KEYS.sidebarCollapsed, nowCollapsed ? 'true' : 'false');
|
||||
syncSubmenuDisplayForState(nowCollapsed);
|
||||
updateSidebarNavOffset();
|
||||
updateSidebarStateClass();
|
||||
updateSidebarWidth();
|
||||
setTimeout(updateSidebarWidth, 250);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -121,14 +124,20 @@
|
||||
body.classList.remove('ots-sidebar-collapsed');
|
||||
document.documentElement.classList.remove('ots-sidebar-collapsed');
|
||||
localStorage.setItem(STORAGE_KEYS.sidebarCollapsed, 'false');
|
||||
syncSubmenuDisplayForState(false);
|
||||
updateSidebarNavOffset();
|
||||
updateSidebarStateClass();
|
||||
updateSidebarWidth();
|
||||
setTimeout(updateSidebarWidth, 250);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize sidebar section toggles
|
||||
initSidebarSectionToggles();
|
||||
|
||||
// Inject flyout headers (icon + label) into each submenu for collapsed state
|
||||
buildFlyoutHeaders();
|
||||
|
||||
// Close sidebar when clicking outside on mobile
|
||||
document.addEventListener('click', function(e) {
|
||||
if (window.innerWidth <= 768) {
|
||||
@@ -147,12 +156,10 @@
|
||||
* This function is kept as a no-op for backward compatibility.
|
||||
*/
|
||||
function updateSidebarWidth() {
|
||||
// No-op: CSS handles layout via body.ots-sidebar-collapsed class
|
||||
if (window.__otsDebug) {
|
||||
const sidebar = document.querySelector('.ots-sidebar');
|
||||
const collapsed = sidebar ? sidebar.classList.contains('collapsed') : false;
|
||||
console.log('[OTS] updateSidebarWidth (no-op, CSS-driven)', { collapsed });
|
||||
}
|
||||
const sidebar = document.querySelector('.ots-sidebar');
|
||||
if (!sidebar) return;
|
||||
const w = sidebar.offsetWidth;
|
||||
document.documentElement.style.setProperty('--ots-sidebar-actual-width', w + 'px');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,39 +167,12 @@
|
||||
* so nav items always begin below the header (logo + buttons).
|
||||
*/
|
||||
function updateSidebarNavOffset() {
|
||||
const sidebar = document.querySelector('.ots-sidebar');
|
||||
if (!sidebar) return;
|
||||
const header = sidebar.querySelector('.sidebar-header');
|
||||
const nav = sidebar.querySelector('.sidebar-nav, .ots-sidebar-nav');
|
||||
if (!nav) return;
|
||||
// Calculate header bottom relative to the sidebar top (so it works with scrolling)
|
||||
const sidebarRect = sidebar.getBoundingClientRect();
|
||||
const headerRect = header ? header.getBoundingClientRect() : null;
|
||||
let offset = 0;
|
||||
if (headerRect) {
|
||||
offset = Math.max(0, Math.ceil(headerRect.bottom - sidebarRect.top));
|
||||
} else if (header) {
|
||||
offset = header.offsetHeight || 0;
|
||||
}
|
||||
// Add a small gap so nav doesn't touch the header edge
|
||||
const gap = 8;
|
||||
const paddingTop = offset > 0 ? offset + gap : '';
|
||||
// apply as inline style to ensure it overrides static CSS rules
|
||||
if (paddingTop) {
|
||||
// Use setProperty with priority so it overrides stylesheet !important rules
|
||||
try {
|
||||
nav.style.setProperty('padding-top', `${paddingTop}px`, 'important');
|
||||
} catch (err) {
|
||||
// fallback
|
||||
nav.style.paddingTop = `${paddingTop}px`;
|
||||
}
|
||||
} else {
|
||||
// remove inline override
|
||||
try {
|
||||
nav.style.removeProperty('padding-top');
|
||||
} catch (err) {
|
||||
nav.style.paddingTop = '';
|
||||
}
|
||||
/* No-op: sidebar uses flex-direction:column so the header and
|
||||
nav content are separate flex children that never overlap.
|
||||
Previously this set padding-top:~72px which created a huge gap. */
|
||||
var nav = document.querySelector('.ots-sidebar .sidebar-nav, .ots-sidebar .ots-sidebar-nav');
|
||||
if (nav) {
|
||||
try { nav.style.removeProperty('padding-top'); } catch(e) { nav.style.paddingTop = ''; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,6 +197,75 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build flyout headers for each sidebar-submenu.
|
||||
* Pulls the icon class(es) and label from the parent group toggle
|
||||
* and injects a styled header <li> at the top of the submenu.
|
||||
* Idempotent — skips submenus that already have a header.
|
||||
*/
|
||||
function buildFlyoutHeaders() {
|
||||
var groups = document.querySelectorAll('.sidebar-group');
|
||||
groups.forEach(function(group) {
|
||||
var submenu = group.querySelector('.sidebar-submenu');
|
||||
if (!submenu) return;
|
||||
// Don't inject twice
|
||||
if (submenu.querySelector('.flyout-header')) return;
|
||||
|
||||
var toggle = group.querySelector('.sidebar-group-toggle');
|
||||
if (!toggle) return;
|
||||
|
||||
// Grab the icon element's class list and the label text
|
||||
var iconEl = toggle.querySelector('.ots-nav-icon');
|
||||
var textEl = toggle.querySelector('.ots-nav-text');
|
||||
if (!textEl) return;
|
||||
|
||||
var label = textEl.textContent.trim();
|
||||
|
||||
// Build the header <li>
|
||||
var header = document.createElement('li');
|
||||
header.className = 'flyout-header';
|
||||
header.setAttribute('aria-hidden', 'true');
|
||||
|
||||
// Clone the icon
|
||||
if (iconEl) {
|
||||
var icon = document.createElement('span');
|
||||
icon.className = iconEl.className; // copies all fa classes
|
||||
icon.classList.add('flyout-header-icon');
|
||||
icon.setAttribute('aria-hidden', 'true');
|
||||
header.appendChild(icon);
|
||||
}
|
||||
|
||||
var text = document.createElement('span');
|
||||
text.className = 'flyout-header-text';
|
||||
text.textContent = label;
|
||||
header.appendChild(text);
|
||||
|
||||
submenu.insertBefore(header, submenu.firstChild);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* When toggling between collapsed/expanded, sync all submenu inline
|
||||
* display styles so that:
|
||||
* - Collapsed: no inline display → CSS :hover handles flyouts
|
||||
* - Expanded: inline display block/none based on is-open state
|
||||
*/
|
||||
function syncSubmenuDisplayForState(isCollapsed) {
|
||||
var groups = document.querySelectorAll('.sidebar-group');
|
||||
groups.forEach(function(group) {
|
||||
var submenu = group.querySelector('.sidebar-submenu');
|
||||
if (!submenu) return;
|
||||
if (isCollapsed) {
|
||||
// Remove inline display so CSS visibility/opacity hover rules work
|
||||
submenu.style.removeProperty('display');
|
||||
} else {
|
||||
// Expanded mode: show/hide based on is-open class
|
||||
var isOpen = group.classList.contains('is-open');
|
||||
submenu.style.display = isOpen ? 'block' : 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize sidebar section collapse/expand functionality
|
||||
*/
|
||||
@@ -231,7 +280,16 @@
|
||||
const caret = toggle.querySelector('.sidebar-group-caret');
|
||||
if (submenu) {
|
||||
const isOpen = group.classList.contains('is-open');
|
||||
submenu.style.display = isOpen ? 'block' : 'none';
|
||||
// Only set inline display when sidebar is NOT collapsed;
|
||||
// collapsed state uses CSS :hover to show flyout menus.
|
||||
const sidebarEl = document.querySelector('.ots-sidebar');
|
||||
const isCollapsed = sidebarEl && sidebarEl.classList.contains('collapsed');
|
||||
if (!isCollapsed) {
|
||||
submenu.style.display = isOpen ? 'block' : 'none';
|
||||
} else {
|
||||
// Clear any leftover inline display so CSS :hover can work
|
||||
submenu.style.removeProperty('display');
|
||||
}
|
||||
toggle.setAttribute('aria-expanded', isOpen.toString());
|
||||
}
|
||||
|
||||
@@ -242,6 +300,12 @@
|
||||
const submenu = group ? group.querySelector('.sidebar-submenu') : null;
|
||||
if (!submenu) return;
|
||||
|
||||
const sidebarEl = document.querySelector('.ots-sidebar');
|
||||
const isCollapsed = sidebarEl && sidebarEl.classList.contains('collapsed');
|
||||
|
||||
// When collapsed, don't toggle submenus on click — hover handles it
|
||||
if (isCollapsed) return;
|
||||
|
||||
const isOpen = group.classList.contains('is-open');
|
||||
group.classList.toggle('is-open', !isOpen);
|
||||
toggle.setAttribute('aria-expanded', (!isOpen).toString());
|
||||
@@ -257,27 +321,6 @@
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Capture-phase handler to override any conflicting listeners
|
||||
document.addEventListener('click', function(e) {
|
||||
const caret = e.target.closest('.sidebar-group-caret');
|
||||
const toggle = e.target.closest('.sidebar-group-toggle');
|
||||
const target = toggle || (caret ? caret.closest('.sidebar-group-toggle') : null);
|
||||
if (!target) return;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const group = target.closest('.sidebar-group');
|
||||
const submenu = group ? group.querySelector('.sidebar-submenu') : null;
|
||||
if (!submenu) return;
|
||||
|
||||
const isOpen = group.classList.contains('is-open');
|
||||
group.classList.toggle('is-open', !isOpen);
|
||||
target.setAttribute('aria-expanded', (!isOpen).toString());
|
||||
submenu.style.display = isOpen ? 'none' : 'block';
|
||||
syncSidebarActiveStates();
|
||||
}, true);
|
||||
}
|
||||
|
||||
function syncSidebarActiveStates() {
|
||||
|
||||
Reference in New Issue
Block a user