202 lines
6.7 KiB
TypeScript
202 lines
6.7 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { BrowserRouter as Router, Routes, Route, Link, Outlet } from 'react-router-dom';
|
|
import logo from './assets/logo.png';
|
|
import './App.css';
|
|
|
|
// Lucide Icons importieren
|
|
import {
|
|
LayoutDashboard,
|
|
Calendar,
|
|
Boxes,
|
|
Image,
|
|
User,
|
|
Settings,
|
|
Monitor,
|
|
MonitorDotIcon,
|
|
LogOut,
|
|
} from 'lucide-react';
|
|
|
|
const sidebarItems = [
|
|
{ name: 'Dashboard', path: '/', icon: LayoutDashboard },
|
|
{ name: 'Termine', path: '/termine', icon: Calendar },
|
|
{ name: 'Ressourcen', path: '/ressourcen', icon: Boxes },
|
|
{ name: 'Infoscreens', path: '/Infoscreens', icon: Monitor },
|
|
{ name: 'Gruppen', path: '/infoscr_groups', icon: MonitorDotIcon },
|
|
{ name: 'Medien', path: '/medien', icon: Image },
|
|
{ name: 'Benutzer', path: '/benutzer', icon: User },
|
|
{ name: 'Einstellungen', path: '/einstellungen', icon: Settings },
|
|
];
|
|
|
|
const Layout: React.FC = () => {
|
|
const [collapsed, setCollapsed] = useState(false);
|
|
|
|
return (
|
|
<div className="flex min-h-screen">
|
|
{/* Sidebar */}
|
|
<aside
|
|
className={`flex flex-col transition-all duration-300 ${collapsed ? 'w-20' : 'w-30'}`}
|
|
style={{
|
|
backgroundColor: '#e5d8c7',
|
|
color: '#78591c',
|
|
fontSize: '1.15rem',
|
|
fontFamily:
|
|
'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif',
|
|
}}
|
|
>
|
|
<div
|
|
className="h-20 flex items-center justify-center border-b"
|
|
style={{ borderColor: '#d6c3a6' }}
|
|
>
|
|
<img
|
|
src={logo}
|
|
alt="Logo"
|
|
className="h-12"
|
|
style={{ display: collapsed ? 'none' : 'block' }}
|
|
/>
|
|
</div>
|
|
<button
|
|
className="p-2 focus:outline-none transition-colors"
|
|
style={{
|
|
backgroundColor: '#e5d8c7',
|
|
color: '#78591c',
|
|
}}
|
|
onClick={() => setCollapsed(!collapsed)}
|
|
aria-label={collapsed ? 'Sidebar ausklappen' : 'Sidebar einklappen'}
|
|
onMouseEnter={e => {
|
|
e.currentTarget.style.backgroundColor = '#78591c';
|
|
e.currentTarget.style.color = '#e5d8c7';
|
|
}}
|
|
onMouseLeave={e => {
|
|
e.currentTarget.style.backgroundColor = '#e5d8c7';
|
|
e.currentTarget.style.color = '#78591c';
|
|
}}
|
|
>
|
|
<span style={{ fontSize: 20 }}>{collapsed ? '▶' : '◀'}</span>
|
|
</button>
|
|
<nav className="flex-1 mt-4">
|
|
{sidebarItems.map(item => {
|
|
const Icon = item.icon;
|
|
return (
|
|
<Link
|
|
key={item.path}
|
|
to={item.path}
|
|
className="flex items-center gap-3 px-6 py-3 transition-colors no-underline"
|
|
style={{
|
|
color: '#78591c',
|
|
textDecoration: 'none',
|
|
whiteSpace: 'nowrap',
|
|
overflow: 'hidden',
|
|
textOverflow: 'ellipsis',
|
|
fontWeight: 500,
|
|
}}
|
|
title={collapsed ? item.name : undefined}
|
|
onMouseEnter={e => {
|
|
e.currentTarget.style.backgroundColor = '#78591c';
|
|
e.currentTarget.style.color = '#e5d8c7';
|
|
}}
|
|
onMouseLeave={e => {
|
|
e.currentTarget.style.backgroundColor = '';
|
|
e.currentTarget.style.color = '#78591c';
|
|
}}
|
|
>
|
|
<Icon size={22} />
|
|
{!collapsed && item.name}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
{/* Abmelden-Button immer ganz unten */}
|
|
<div className="mb-4 mt-auto">
|
|
<button
|
|
className="flex items-center gap-3 px-6 py-3 w-full transition-colors no-underline"
|
|
style={{
|
|
color: '#78591c',
|
|
backgroundColor: '#e5d8c7',
|
|
border: 'none',
|
|
fontWeight: 500,
|
|
cursor: 'pointer',
|
|
textAlign: 'left',
|
|
fontSize: '1.15rem',
|
|
width: '100%',
|
|
}}
|
|
title={collapsed ? 'Abmelden' : undefined}
|
|
onClick={() => {
|
|
// Hier ggf. Logout-Logik einfügen
|
|
window.location.href = '/logout';
|
|
}}
|
|
onMouseEnter={e => {
|
|
e.currentTarget.style.backgroundColor = '#78591c';
|
|
e.currentTarget.style.color = '#e5d8c7';
|
|
}}
|
|
onMouseLeave={e => {
|
|
e.currentTarget.style.backgroundColor = '#e5d8c7';
|
|
e.currentTarget.style.color = '#78591c';
|
|
}}
|
|
>
|
|
<LogOut size={22} />
|
|
{!collapsed && 'Abmelden'}
|
|
</button>
|
|
</div>
|
|
</aside>
|
|
{/* Main Content */}
|
|
<div className="flex-1 flex flex-col">
|
|
{/* Header */}
|
|
<header
|
|
className="flex items-center px-8 shadow"
|
|
style={{
|
|
backgroundColor: '#e5d8c7',
|
|
color: '#78591c',
|
|
height: 'calc(48px + 20px)',
|
|
fontSize: '1.15rem',
|
|
fontFamily:
|
|
'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif',
|
|
}}
|
|
>
|
|
<img
|
|
src={logo}
|
|
alt="Logo"
|
|
className="h-12 mr-4"
|
|
style={{ marginTop: 10, marginBottom: 10 }}
|
|
/>
|
|
<span className="text-2xl font-bold mr-8">Infoscreen-Management</span>
|
|
<span className="ml-auto" style={{ color: '#78591c' }}>
|
|
[Organisationsname]
|
|
</span>
|
|
</header>
|
|
<main className="flex-1 p-8 bg-gray-100">
|
|
<Outlet />
|
|
</main>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const App: React.FC = () => (
|
|
<Router>
|
|
<Routes>
|
|
<Route path="/" element={<Layout />}>
|
|
<Route index element={<Dashboard />} />
|
|
<Route path="termine" element={<Appointments />} />
|
|
<Route path="ressourcen" element={<Ressourcen />} />
|
|
<Route path="Infoscreens" element={<Infoscreens />} />
|
|
<Route path="infoscr_groups" element={<Infoscreen_groups />} />
|
|
<Route path="medien" element={<Medien />} />
|
|
<Route path="benutzer" element={<Benutzer />} />
|
|
<Route path="einstellungen" element={<Einstellungen />} />
|
|
</Route>
|
|
</Routes>
|
|
</Router>
|
|
);
|
|
|
|
export default App;
|
|
|
|
// Dummy Components (können in eigene Dateien ausgelagert werden)
|
|
import Dashboard from './dashboard';
|
|
import Appointments from './appointments';
|
|
import Ressourcen from './ressourcen';
|
|
import Infoscreens from './clients';
|
|
import Infoscreen_groups from './infoscreen_groups';
|
|
import Medien from './medien';
|
|
import Benutzer from './benutzer';
|
|
import Einstellungen from './einstellungen';
|