Merge pull request #146 from gbw/feature/collapsible-mobile-sidebar
feat(ui): add collapsible sidebar for mobile devices
This commit is contained in:
@@ -8,6 +8,51 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
box-shadow: 2px 0 12px rgba(0,0,0,0.15);
|
box-shadow: 2px 0 12px rgba(0,0,0,0.15);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar overlay for mobile */
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 998;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay.active {
|
||||||
|
display: block;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile responsive styles */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 999;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar.open {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[dir='rtl'] .sidebar {
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
[dir='rtl'] .sidebar.open {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo-container {
|
.logo-container {
|
||||||
|
|||||||
@@ -20,6 +20,42 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sidebar toggle button (hidden on desktop) */
|
||||||
|
.sidebar-toggle {
|
||||||
|
display: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #4a5568;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: background-color 0.2s, color 0.2s;
|
||||||
|
margin-right: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-toggle:hover {
|
||||||
|
background-color: #f7fafc;
|
||||||
|
color: #ff5e3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-toggle i {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile responsive styles for top bar */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.top-bar {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.search-container {
|
.search-container {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
|
|||||||
@@ -201,3 +201,13 @@
|
|||||||
[data-theme="dark"] .search-sort-select:focus {
|
[data-theme="dark"] .search-sort-select:focus {
|
||||||
border-color: #ff5e3a;
|
border-color: #ff5e3a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dark theme for mobile sidebar toggle */
|
||||||
|
[data-theme="dark"] .sidebar-toggle {
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .sidebar-toggle:hover {
|
||||||
|
background-color: #334155;
|
||||||
|
color: #ff5e3a;
|
||||||
|
}
|
||||||
|
|||||||
+7
-1
@@ -57,8 +57,10 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Mobile sidebar overlay -->
|
||||||
|
<div class="sidebar-overlay" id="sidebar-overlay"></div>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<a href="/" class="logo-container" style="text-decoration:none;color:inherit;">
|
<a href="/" class="logo-container" style="text-decoration:none;color:inherit;">
|
||||||
|
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
@@ -105,6 +107,10 @@
|
|||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<!-- Top Bar -->
|
<!-- Top Bar -->
|
||||||
<div class="top-bar">
|
<div class="top-bar">
|
||||||
|
<!-- Mobile menu toggle -->
|
||||||
|
<button class="sidebar-toggle" id="sidebar-toggle" aria-label="Toggle navigation menu">
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<i class="fas fa-search search-icon"></i>
|
<i class="fas fa-search search-icon"></i>
|
||||||
<input type="text" id="search-input" data-i18n-placeholder="actions.search" placeholder="Search files, folders...">
|
<input type="text" id="search-input" data-i18n-placeholder="actions.search" placeholder="Search files, folders...">
|
||||||
|
|||||||
@@ -3,6 +3,70 @@
|
|||||||
* Extracted from main.js to keep navigation concerns isolated.
|
* Extracted from main.js to keep navigation concerns isolated.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mobile sidebar toggle functionality
|
||||||
|
*/
|
||||||
|
function initSidebarToggle() {
|
||||||
|
const sidebarToggle = document.getElementById('sidebar-toggle');
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const sidebarOverlay = document.getElementById('sidebar-overlay');
|
||||||
|
|
||||||
|
if (!sidebarToggle || !sidebar || !sidebarOverlay) return;
|
||||||
|
|
||||||
|
function openSidebar() {
|
||||||
|
sidebar.classList.add('open');
|
||||||
|
sidebarOverlay.classList.add('active');
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSidebar() {
|
||||||
|
sidebar.classList.remove('open');
|
||||||
|
sidebarOverlay.classList.remove('active');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSidebar() {
|
||||||
|
if (sidebar.classList.contains('open')) {
|
||||||
|
closeSidebar();
|
||||||
|
} else {
|
||||||
|
openSidebar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle button click
|
||||||
|
sidebarToggle.addEventListener('click', toggleSidebar);
|
||||||
|
|
||||||
|
// Close sidebar when clicking overlay
|
||||||
|
sidebarOverlay.addEventListener('click', closeSidebar);
|
||||||
|
|
||||||
|
// Close sidebar on escape key
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape' && sidebar.classList.contains('open')) {
|
||||||
|
closeSidebar();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close sidebar when navigating (nav item click on mobile)
|
||||||
|
const navItems = sidebar.querySelectorAll('.nav-item');
|
||||||
|
navItems.forEach(item => {
|
||||||
|
item.addEventListener('click', () => {
|
||||||
|
if (window.innerWidth <= 768) {
|
||||||
|
closeSidebar();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Expose functions globally
|
||||||
|
window.sidebarToggle = {
|
||||||
|
open: openSidebar,
|
||||||
|
close: closeSidebar,
|
||||||
|
toggle: toggleSidebar
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize sidebar toggle when DOM is ready
|
||||||
|
document.addEventListener('DOMContentLoaded', initSidebarToggle);
|
||||||
|
|
||||||
// Mapping of section names to their corresponding view flags
|
// Mapping of section names to their corresponding view flags
|
||||||
const VIEW_FLAGS = {
|
const VIEW_FLAGS = {
|
||||||
'files': 'isFilesView',
|
'files': 'isFilesView',
|
||||||
|
|||||||
Reference in New Issue
Block a user