infoscreen-overview in cards

This commit is contained in:
2025-06-23 16:06:00 +00:00
parent 76f6baf533
commit 6e38ca477a
18 changed files with 476 additions and 124 deletions

View File

@@ -1,113 +1,156 @@
// import 'react-app-polyfill/ie11'; // optional, falls benötigt
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';
import React from 'react';
// Lucide Icons importieren
import {
ScheduleComponent,
Day,
Week,
WorkWeek,
Month,
Agenda,
TimelineViews,
TimelineMonth,
Inject,
ViewsDirective,
ViewDirective,
ResourcesDirective,
ResourceDirective,
} from '@syncfusion/ej2-react-schedule';
import { L10n, loadCldr, setCulture } from '@syncfusion/ej2-base';
import * as de from 'cldr-data/main/de/ca-gregorian.json';
import * as numbers from 'cldr-data/main/de/numbers.json';
import * as timeZoneNames from 'cldr-data/main/de/timeZoneNames.json';
import * as numberingSystems from 'cldr-data/supplemental/numberingSystems.json';
LayoutDashboard,
Calendar,
Boxes,
Users,
UserSquare,
Image,
User,
Settings,
} from 'lucide-react';
// CLDR-Daten laden
loadCldr(
(de as unknown as { default: object }).default,
(numbers as unknown as { default: object }).default,
(timeZoneNames as unknown as { default: object }).default,
(numberingSystems as unknown as { default: object }).default
);
// Deutsche Lokalisierung für den Scheduler
L10n.load({
de: {
schedule: {
day: 'Tag',
week: 'Woche',
workWeek: 'Arbeitswoche',
month: 'Monat',
agenda: 'Agenda',
today: 'Heute',
noEvents: 'Keine Termine',
},
},
});
// Kultur setzen
setCulture('de');
// Ressourcen-Daten
const resources = [
{ text: 'Raum A', id: 1, color: '#1aaa55' },
{ text: 'Raum B', id: 2, color: '#357cd2' },
{ text: 'Raum C', id: 3, color: '#7fa900' },
const sidebarItems = [
{ name: 'Dashboard', path: '/', icon: LayoutDashboard },
{ name: 'Termine', path: '/termine', icon: Calendar },
{ name: 'Ressourcen', path: '/ressourcen', icon: Boxes },
{ name: 'Infoscreens', path: '/Infoscreens', icon: Users },
{ name: 'Gruppen', path: '/gruppen', icon: UserSquare },
{ name: 'Medien', path: '/medien', icon: Image },
{ name: 'Benutzer', path: '/benutzer', icon: User },
{ name: 'Einstellungen', path: '/einstellungen', icon: Settings },
];
// Dummy-Termine generieren
const now = new Date();
const appointments = Array.from({ length: 10 }).map((_, i) => {
const dayOffset = Math.floor(i * 1.4); // verteilt auf 14 Tage
const start = new Date(now);
start.setDate(now.getDate() + dayOffset);
start.setHours(9 + (i % 4), 0, 0, 0);
const end = new Date(start);
end.setHours(start.getHours() + 1);
const Layout: React.FC = () => {
const [collapsed, setCollapsed] = useState(false);
return {
Id: i + 1,
Subject: `Termin ${i + 1}`,
StartTime: start,
EndTime: end,
ResourceId: (i % 3) + 1,
Location: resources[i % 3].text,
};
});
const App: React.FC = () => {
return (
<div className="p-8 bg-gray-100 min-h-screen">
<h1 className="text-2xl font-bold mb-4">Infoscreen Kalendersteuerung</h1>
<ScheduleComponent
height="650px"
locale="de"
currentView="TimelineWeek"
eventSettings={{ dataSource: appointments }}
group={{ resources: ['Räume'] }}
<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',
}}
>
<ViewsDirective>
<ViewDirective option="Week" />
<ViewDirective option="TimelineWeek" />
<ViewDirective option="Month" />
<ViewDirective option="TimelineMonth" />
</ViewsDirective>
<ResourcesDirective>
<ResourceDirective
field="ResourceId"
title="Räume"
name="Räume"
allowMultiple={false}
dataSource={resources}
textField="text"
idField="id"
colorField="color"
<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' }}
/>
</ResourcesDirective>
<Inject services={[Day, Week, WorkWeek, Month, Agenda, TimelineViews, TimelineMonth]} />
</ScheduleComponent>
</div>
<button
className="p-2 focus:outline-none hover:bg-[#d6c3a6] transition-colors"
onClick={() => setCollapsed(!collapsed)}
aria-label={collapsed ? 'Sidebar ausklappen' : 'Sidebar einklappen'}
>
<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>
</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="gruppen" element={<Gruppen />} />
<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 Gruppen from './gruppen';
import Medien from './medien';
import Benutzer from './benutzer';
import Einstellungen from './einstellungen';