push newest version
This commit is contained in:
@@ -1,14 +1,32 @@
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import { Link, useLocation, useNavigate } from 'react-router-dom'
|
||||
import { useAuth } from '../contexts/AuthContext'
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
const Sidebar = ({ isOpen, setIsOpen }) => {
|
||||
const location = useLocation()
|
||||
const navigate = useNavigate()
|
||||
const { user, logout } = useAuth()
|
||||
const [expandedMenus, setExpandedMenus] = useState({})
|
||||
|
||||
const menuItems = [
|
||||
{ path: '/', label: 'Home', icon: '🏠' },
|
||||
{ path: '/spaces', label: 'Spaces', icon: '📁' },
|
||||
{ path: '/audit-logs', label: 'Audit Log', icon: '📋' },
|
||||
{ path: '/impressum', label: 'Impressum', icon: 'ℹ️' },
|
||||
]
|
||||
|
||||
// Settings mit Unterpunkten
|
||||
const settingsMenu = {
|
||||
label: 'Settings',
|
||||
icon: '⚙️',
|
||||
path: '/settings',
|
||||
subItems: [
|
||||
{ path: '/settings/users', label: 'User', icon: '👥' },
|
||||
]
|
||||
}
|
||||
|
||||
const profileItem = { path: '/profile', label: 'Profil', icon: '👤' }
|
||||
|
||||
const isActive = (path) => {
|
||||
if (path === '/') {
|
||||
return location.pathname === '/'
|
||||
@@ -16,6 +34,27 @@ const Sidebar = ({ isOpen, setIsOpen }) => {
|
||||
return location.pathname.startsWith(path)
|
||||
}
|
||||
|
||||
const toggleMenu = (menuPath) => {
|
||||
setExpandedMenus(prev => ({
|
||||
...prev,
|
||||
[menuPath]: !prev[menuPath]
|
||||
}))
|
||||
}
|
||||
|
||||
const isMenuExpanded = (menuPath) => {
|
||||
return expandedMenus[menuPath] || false
|
||||
}
|
||||
|
||||
// Automatisch Settings-Menü expandieren, wenn auf einer Settings-Seite
|
||||
useEffect(() => {
|
||||
if (location.pathname.startsWith('/settings')) {
|
||||
setExpandedMenus(prev => ({
|
||||
...prev,
|
||||
'/settings': true
|
||||
}))
|
||||
}
|
||||
}, [location.pathname])
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Overlay for mobile */}
|
||||
@@ -63,8 +102,8 @@ const Sidebar = ({ isOpen, setIsOpen }) => {
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<nav className="px-2 py-4 overflow-hidden">
|
||||
<ul className="space-y-2">
|
||||
<nav className="px-2 py-4 overflow-hidden flex flex-col h-[calc(100%-4rem)]">
|
||||
<ul className="space-y-2 flex-1">
|
||||
{menuItems.map((item) => (
|
||||
<li key={item.path}>
|
||||
<Link
|
||||
@@ -87,7 +126,104 @@ const Sidebar = ({ isOpen, setIsOpen }) => {
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
|
||||
{/* Settings Menu mit Unterpunkten */}
|
||||
<li>
|
||||
<button
|
||||
onClick={() => isOpen && toggleMenu(settingsMenu.path)}
|
||||
className={`w-full flex items-center px-3 py-3 rounded-lg transition-all duration-200 ${
|
||||
isActive(settingsMenu.path)
|
||||
? 'bg-slate-700 text-white font-semibold shadow-md'
|
||||
: 'text-slate-300 hover:bg-slate-700/50 hover:text-white'
|
||||
}`}
|
||||
title={!isOpen ? settingsMenu.label : ''}
|
||||
>
|
||||
<span className={`text-xl flex-shrink-0 ${isOpen ? 'mr-3' : 'mx-auto'}`}>
|
||||
{settingsMenu.icon}
|
||||
</span>
|
||||
{isOpen && (
|
||||
<>
|
||||
<span className="whitespace-nowrap overflow-hidden">
|
||||
{settingsMenu.label}
|
||||
</span>
|
||||
<svg
|
||||
className={`w-4 h-4 ml-auto flex-shrink-0 transition-transform duration-200 ${
|
||||
isMenuExpanded(settingsMenu.path) ? 'rotate-90' : ''
|
||||
}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
{isOpen && isMenuExpanded(settingsMenu.path) && settingsMenu.subItems && (
|
||||
<ul className="ml-4 mt-1 space-y-1">
|
||||
{settingsMenu.subItems.map((subItem) => (
|
||||
<li key={subItem.path}>
|
||||
<Link
|
||||
to={subItem.path}
|
||||
className={`flex items-center px-3 py-2 rounded-lg transition-all duration-200 ${
|
||||
isActive(subItem.path)
|
||||
? 'bg-slate-600 text-white font-semibold'
|
||||
: 'text-slate-400 hover:bg-slate-700/50 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<span className="text-lg flex-shrink-0 mr-2">
|
||||
{subItem.icon}
|
||||
</span>
|
||||
<span className="whitespace-nowrap overflow-hidden">
|
||||
{subItem.label}
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
{/* Profil-Eintrag und Logout am unteren Ende */}
|
||||
<div className="mt-auto pt-2 border-t border-slate-700/50 space-y-2">
|
||||
<Link
|
||||
to={profileItem.path}
|
||||
className={`flex items-center px-3 py-3 rounded-lg transition-all duration-200 ${
|
||||
isActive(profileItem.path)
|
||||
? 'bg-slate-700 text-white font-semibold shadow-md'
|
||||
: 'text-slate-300 hover:bg-slate-700/50 hover:text-white'
|
||||
}`}
|
||||
title={!isOpen ? (user?.username || profileItem.label) : ''}
|
||||
>
|
||||
<span className={`text-xl flex-shrink-0 ${isOpen ? 'mr-3' : 'mx-auto'}`}>
|
||||
{profileItem.icon}
|
||||
</span>
|
||||
{isOpen && (
|
||||
<span className="whitespace-nowrap overflow-hidden">
|
||||
{user?.username || profileItem.label}
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
<button
|
||||
onClick={() => {
|
||||
logout()
|
||||
navigate('/login')
|
||||
}}
|
||||
className={`w-full flex items-center px-3 py-3 rounded-lg transition-all duration-200 text-slate-300 hover:bg-red-600/20 hover:text-red-400 ${
|
||||
isOpen ? '' : 'justify-center'
|
||||
}`}
|
||||
title={!isOpen ? 'Abmelden' : ''}
|
||||
>
|
||||
<span className={`text-xl flex-shrink-0 ${isOpen ? 'mr-3' : ''}`}>
|
||||
🚪
|
||||
</span>
|
||||
{isOpen && (
|
||||
<span className="whitespace-nowrap overflow-hidden">
|
||||
Abmelden
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user