226 lines
7.9 KiB
JavaScript
226 lines
7.9 KiB
JavaScript
/* Sage Modern UI Shell Theme & Layout Controller
|
|
Handles: theme switching (dark/light), sidebar collapse, localStorage persistence
|
|
*/
|
|
(function() {
|
|
'use strict';
|
|
|
|
var THEME_KEY = 'sage_ui_theme';
|
|
var SIDEBAR_KEY = 'sage_sidebar_collapsed';
|
|
|
|
// Initialize theme on page load
|
|
function initTheme() {
|
|
var saved = null;
|
|
try { saved = localStorage.getItem(THEME_KEY); } catch(e) {}
|
|
var theme = saved || 'dark';
|
|
document.documentElement.setAttribute('data-theme', theme);
|
|
updateThemeIcon(theme);
|
|
}
|
|
|
|
// Toggle between dark and light
|
|
function toggleTheme() {
|
|
var current = document.documentElement.getAttribute('data-theme') || 'dark';
|
|
var next = current === 'dark' ? 'light' : 'dark';
|
|
document.documentElement.setAttribute('data-theme', next);
|
|
try { localStorage.setItem(THEME_KEY, next); } catch(e) {}
|
|
updateThemeIcon(next);
|
|
}
|
|
|
|
// Update the theme toggle icon based on current theme
|
|
function updateThemeIcon(theme) {
|
|
var btn = document.getElementById('theme_toggle_btn');
|
|
if (!btn) return;
|
|
if (theme === 'light') {
|
|
// Show moon icon (switch to dark)
|
|
btn.innerHTML = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>';
|
|
} else {
|
|
// Show sun icon (switch to light)
|
|
btn.innerHTML = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>';
|
|
}
|
|
}
|
|
|
|
// Initialize sidebar state
|
|
function initSidebar() {
|
|
var collapsed = false;
|
|
try { collapsed = localStorage.getItem(SIDEBAR_KEY) === 'true'; } catch(e) {}
|
|
|
|
// Auto-collapse on mobile
|
|
if (isMobile()) {
|
|
collapsed = true;
|
|
}
|
|
|
|
var sidebar = document.getElementById('sage_sidebar');
|
|
if (sidebar && collapsed) {
|
|
sidebar.classList.add('collapsed');
|
|
}
|
|
}
|
|
|
|
// Handle window resize - auto-collapse on mobile
|
|
function handleResize() {
|
|
var sidebar = document.getElementById('sage_sidebar');
|
|
if (!sidebar) return;
|
|
|
|
if (isMobile() && !sidebar.classList.contains('collapsed')) {
|
|
sidebar.classList.add('collapsed');
|
|
try { localStorage.setItem(SIDEBAR_KEY, 'true'); } catch(e) {}
|
|
updateSidebarIcon(true);
|
|
}
|
|
}
|
|
|
|
// Check if we're on mobile viewport
|
|
function isMobile() {
|
|
return window.innerWidth <= 768;
|
|
}
|
|
|
|
// Close sidebar when clicking outside on mobile
|
|
function setupMobileOverlay() {
|
|
document.addEventListener('click', function(e) {
|
|
if (!isMobile()) return;
|
|
var sidebar = document.getElementById('sage_sidebar');
|
|
var toggleBtn = document.getElementById('sidebar_toggle_btn');
|
|
if (!sidebar || sidebar.classList.contains('collapsed')) return;
|
|
// If click is outside sidebar and toggle button, close sidebar
|
|
if (!sidebar.contains(e.target) && (!toggleBtn || !toggleBtn.contains(e.target))) {
|
|
sidebar.classList.add('collapsed');
|
|
try { localStorage.setItem(SIDEBAR_KEY, 'true'); } catch(ex) {}
|
|
updateSidebarIcon(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateSidebarIcon(isCollapsed) {
|
|
var btn = document.getElementById('sidebar_toggle_btn');
|
|
if (!btn) return;
|
|
if (isCollapsed) {
|
|
btn.innerHTML = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="13 17 18 12 13 7"/><polyline points="6 17 11 12 6 7"/></svg>';
|
|
} else {
|
|
btn.innerHTML = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="11 17 6 12 11 7"/><polyline points="18 17 13 12 18 7"/></svg>';
|
|
}
|
|
}
|
|
|
|
// Toggle sidebar collapse
|
|
function toggleSidebar() {
|
|
var sidebar = document.getElementById('sage_sidebar');
|
|
if (!sidebar) return;
|
|
sidebar.classList.toggle('collapsed');
|
|
var isCollapsed = sidebar.classList.contains('collapsed');
|
|
try { localStorage.setItem(SIDEBAR_KEY, isCollapsed); } catch(e) {}
|
|
updateSidebarIcon(isCollapsed);
|
|
// Toggle Menu widget collapse state
|
|
if (typeof bricks !== 'undefined') {
|
|
var menu = bricks.getWidgetById('global_nav_menu', bricks.app);
|
|
if (menu && menu.toggle_collapse) {
|
|
menu.toggle_collapse();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize SPA Router
|
|
function initRouter() {
|
|
if (typeof bricks === 'undefined' || !bricks.Router) {
|
|
console.log('[Shell] Router not available');
|
|
return;
|
|
}
|
|
bricks.Router.init({
|
|
targets: [
|
|
{ id: 'sage_main_content', param: 'page' }
|
|
]
|
|
});
|
|
}
|
|
|
|
// Reload global menu after login/logout
|
|
window.sageReloadMenu = async function() {
|
|
if (typeof bricks === 'undefined') return;
|
|
var sidebar = bricks.getWidgetById('sage_sidebar', bricks.app);
|
|
if (!sidebar) {
|
|
console.log('[Shell] sage_sidebar not found');
|
|
return;
|
|
}
|
|
// Check if sidebar is currently collapsed before clearing
|
|
var isCollapsed = sidebar.el && sidebar.el.classList.contains('collapsed');
|
|
// Clear existing children
|
|
sidebar.subwidgets.forEach(function(w) { w.destroy && w.destroy(); });
|
|
sidebar.subwidgets = [];
|
|
sidebar.el.innerHTML = '';
|
|
// Rebuild menu urlwidget
|
|
var menuUrl = bricks.app.baseUrl + '/global_menu.ui?_webbricks_=1';
|
|
var desc = {
|
|
"widgettype": "urlwidget",
|
|
"options": { "url": menuUrl }
|
|
};
|
|
try {
|
|
var w = await bricks.widgetBuild(desc, sidebar);
|
|
if (w) {
|
|
sidebar.addSubWidget(w);
|
|
// Re-apply collapsed state to newly built menu
|
|
if (isCollapsed) {
|
|
var menu = bricks.getWidgetById('global_nav_menu', bricks.app);
|
|
if (menu && menu.collapse) {
|
|
menu.collapse();
|
|
}
|
|
}
|
|
console.log('[Shell] Menu reloaded');
|
|
}
|
|
} catch(e) {
|
|
console.log('[Shell] Menu reload error:', e);
|
|
}
|
|
};
|
|
|
|
// Run on DOM ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initTheme();
|
|
initSidebar();
|
|
initRouter();
|
|
setupMobileOverlay();
|
|
window.addEventListener('resize', handleResize);
|
|
});
|
|
} else {
|
|
initTheme();
|
|
initSidebar();
|
|
initRouter();
|
|
setupMobileOverlay();
|
|
window.addEventListener('resize', handleResize);
|
|
}
|
|
|
|
// Bricks widgets render asynchronously after DOMContentLoaded.
|
|
// Retry updateThemeIcon until the button element exists.
|
|
(function retryThemeIcon() {
|
|
var btn = document.getElementById('theme_toggle_btn');
|
|
if (btn) {
|
|
var theme = document.documentElement.getAttribute('data-theme') || 'dark';
|
|
updateThemeIcon(theme);
|
|
} else {
|
|
setTimeout(retryThemeIcon, 200);
|
|
}
|
|
})();
|
|
|
|
// Retry sidebar icon init until the button element exists
|
|
(function retrySidebarIcon() {
|
|
var sidebar = document.getElementById('sage_sidebar');
|
|
var btn = document.getElementById('sidebar_toggle_btn');
|
|
if (btn && sidebar) {
|
|
var isCollapsed = sidebar.classList.contains('collapsed');
|
|
updateSidebarIcon(isCollapsed);
|
|
// Apply collapsed state to Menu if sidebar was already collapsed
|
|
if (isCollapsed && typeof bricks !== 'undefined') {
|
|
var menu = bricks.getWidgetById('global_nav_menu', bricks.app);
|
|
if (menu && menu.collapse) {
|
|
menu.collapse();
|
|
} else {
|
|
setTimeout(retrySidebarIcon, 200);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
setTimeout(retrySidebarIcon, 200);
|
|
}
|
|
})();
|
|
|
|
// Expose global functions for bricks bind access
|
|
window.sageToggleTheme = toggleTheme;
|
|
window.sageToggleSidebar = toggleSidebar;
|
|
window.sageInitTheme = initTheme;
|
|
window.sageInitSidebar = initSidebar;
|
|
|
|
})();
|