diff --git a/wwwroot/shell_theme.css b/wwwroot/shell_theme.css
index 9215966..6d5cdd9 100644
--- a/wwwroot/shell_theme.css
+++ b/wwwroot/shell_theme.css
@@ -128,7 +128,9 @@ body {
overflow-y: auto;
overflow-x: hidden;
flex-shrink: 0;
- transition: width 0.25s ease;
+ transition: width 0.3s ease, transform 0.3s ease;
+ position: relative;
+ z-index: 50;
}
.sage-sidebar.collapsed {
@@ -141,12 +143,48 @@ body {
overflow: hidden;
}
+/* Mobile: sidebar as overlay */
+@media (max-width: 768px) {
+ .sage-sidebar {
+ position: fixed;
+ left: 0;
+ top: var(--sage-topbar-height);
+ height: calc(100vh - var(--sage-topbar-height));
+ transform: translateX(0);
+ box-shadow: var(--sage-shadow-lg);
+ }
+
+ .sage-sidebar.collapsed {
+ transform: translateX(-100%);
+ width: var(--sage-sidebar-width); /* Keep full width when hidden on mobile */
+ }
+
+ .sage-main {
+ width: 100%;
+ }
+}
+
.sage-main {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: 24px;
background-color: var(--sage-bg-primary);
+ min-width: 0; /* Prevent flex item from overflowing */
+ transition: margin-left 0.3s ease;
+}
+
+/* Responsive padding for mobile */
+@media (max-width: 768px) {
+ .sage-main {
+ padding: 16px;
+ }
+}
+
+@media (max-width: 480px) {
+ .sage-main {
+ padding: 12px;
+ }
}
/* ===== Stat Cards ===== */
@@ -719,18 +757,43 @@ body {
color: var(--sage-text-secondary);
}
-/* ===== Responsive ===== */
+/* ===== Responsive - Topbar ===== */
@media (max-width: 768px) {
- .sage-sidebar {
- position: fixed;
- left: 0;
- top: var(--sage-topbar-height);
- bottom: 0;
- z-index: 200;
- transform: translateX(-100%);
- transition: transform 0.25s ease;
+ .sage-topbar {
+ padding: 0 8px;
+ gap: 6px;
}
- .sage-sidebar.mobile-open {
- transform: translateX(0);
+ .sage-brand-title {
+ font-size: 16px;
+ }
+}
+
+@media (max-width: 480px) {
+ .sage-brand-title {
+ display: none;
+ }
+}
+
+/* ===== Responsive - Stat Cards ===== */
+@media (max-width: 768px) {
+ .stat-card {
+ padding: 14px;
+ }
+ .stat-card .stat-value {
+ font-size: 22px;
+ }
+ .stat-card .stat-label {
+ font-size: 12px;
+ }
+ .stat-card .stat-icon {
+ width: 32px;
+ height: 32px;
+ margin-bottom: 8px;
+ }
+ .quick-link {
+ padding: 14px;
+ }
+ .section-title {
+ font-size: 16px;
}
}
diff --git a/wwwroot/shell_theme.js b/wwwroot/shell_theme.js
index 2b86ddb..89f8de3 100644
--- a/wwwroot/shell_theme.js
+++ b/wwwroot/shell_theme.js
@@ -42,12 +42,61 @@
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 = '';
+ } else {
+ btn.innerHTML = '';
+ }
+ }
+
// Toggle sidebar collapse
function toggleSidebar() {
var sidebar = document.getElementById('sage_sidebar');
@@ -55,16 +104,7 @@
sidebar.classList.toggle('collapsed');
var isCollapsed = sidebar.classList.contains('collapsed');
try { localStorage.setItem(SIDEBAR_KEY, isCollapsed); } catch(e) {}
-
- // Update toggle icon
- var btn = document.getElementById('sidebar_toggle_btn');
- if (btn) {
- if (isCollapsed) {
- btn.innerHTML = '';
- } else {
- btn.innerHTML = '';
- }
- }
+ updateSidebarIcon(isCollapsed);
}
// Initialize SPA Router
@@ -115,11 +155,15 @@
initTheme();
initSidebar();
initRouter();
+ setupMobileOverlay();
+ window.addEventListener('resize', handleResize);
});
} else {
initTheme();
initSidebar();
initRouter();
+ setupMobileOverlay();
+ window.addEventListener('resize', handleResize);
}
// Bricks widgets render asynchronously after DOMContentLoaded.
@@ -134,6 +178,18 @@
}
})();
+ // 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);
+ } else {
+ setTimeout(retrySidebarIcon, 200);
+ }
+ })();
+
// Expose global functions for bricks bind access
window.sageToggleTheme = toggleTheme;
window.sageToggleSidebar = toggleSidebar;