Files
p42.f-w/frontend/src/pages/Home.jsx
T
guyg1474andClaude Opus 5.5 dd58b3d1f8 P42 Dashboard: erster Stand
FastAPI-Backend und React-Frontend mit Konten, Sendungsverfolgung,
Projekt-Artikeln, Vorrat & Einkauf mit Rezeptabgleich, Reise-Weltkarte,
Kanban-Projekten mit Priorität, Server-Monitoring und den Designs
Matrix und Blackwall. Betrieb per Docker hinter nginx (siehe DEPLOY.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:08:11 +02:00

85 lines
3.8 KiB
React

import { useRef } from 'react';
import { Link } from 'react-router-dom';
import LinksDialog from '../components/LinksDialog.jsx';
import Tracking from '../components/Tracking.jsx';
import { LINK_SERVICES, useLinks } from '../links.jsx';
const svg = {
fill: 'none', stroke: 'currentColor', strokeWidth: 1.8, strokeLinecap: 'round', strokeLinejoin: 'round', viewBox: '0 0 24 24',
};
const ICONS = {
jellyfin: <svg {...svg}><rect x="2" y="5" width="20" height="14" rx="2" /><path d="m10 9 5 3-5 3z" /></svg>,
audiobookshelf: <svg {...svg}><path d="M3 18v-6a9 9 0 0 1 18 0v6" /><path d="M21 19a2 2 0 0 1-2 2h-1v-6h3zM3 19a2 2 0 0 0 2 2h1v-6H3z" /></svg>,
homer: <svg {...svg}><rect x="3" y="3" width="7" height="7" rx="1.5" /><rect x="14" y="3" width="7" height="7" rx="1.5" /><rect x="3" y="14" width="7" height="7" rx="1.5" /><rect x="14" y="14" width="7" height="7" rx="1.5" /></svg>,
projekte: <svg {...svg}><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /></svg>,
haushalt: <svg {...svg}><path d="M3 4h2l2.4 11.2a2 2 0 0 0 2 1.6h7.7a2 2 0 0 0 2-1.5L21 8H6.2" /><circle cx="10" cy="20" r="1.2" /><circle cx="17" cy="20" r="1.2" /></svg>,
reisen: <svg {...svg}><circle cx="12" cy="12" r="9" /><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /></svg>,
kanban: <svg {...svg}><rect x="3" y="4" width="5" height="16" rx="1" /><rect x="10" y="4" width="5" height="10" rx="1" /><rect x="17" y="4" width="4" height="7" rx="1" /></svg>,
monitoring: <svg {...svg}><rect x="3" y="4" width="18" height="6" rx="1.5" /><rect x="3" y="14" width="18" height="6" rx="1.5" /><path d="M7 7h.01M7 17h.01" /></svg>,
};
export default function Home() {
const { links } = useLinks();
const dialog = useRef(null);
const editLinks = () => dialog.current.showModal();
return (
<>
<Tracking />
<section className="tiles-section" aria-labelledby="tiles-title">
<div className="tiles-head">
<h2 id="tiles-title" className="section-title">Schnellzugriff</h2>
<button className="link-btn" type="button" onClick={editLinks}>✎ Links bearbeiten</button>
</div>
<div className="tiles">
{LINK_SERVICES.map(({ key, name, description }) =>
links[key] ? (
<a key={key} className="tile" href={links[key]} target="_blank" rel="noopener noreferrer">
{ICONS[key]}
<strong>{name}</strong>
<small>{description}</small>
</a>
) : (
// Ohne Link öffnet die Kachel direkt den Bearbeiten-Dialog
<button key={key} className="tile tile-empty" type="button" onClick={editLinks}>
{ICONS[key]}
<strong>{name}</strong>
<small>Link festlegen …</small>
</button>
),
)}
<Link className="tile" to="/projekte">
{ICONS.projekte}
<strong>P42 Projekte</strong>
<small>Übersicht aller Projekte</small>
</Link>
<Link className="tile" to="/haushalt">
{ICONS.haushalt}
<strong>Vorrat &amp; Einkauf</strong>
<small>Gemeinsame Einkaufsliste</small>
</Link>
<Link className="tile" to="/reisen">
{ICONS.reisen}
<strong>Reisen</strong>
<small>Meine Weltkarte</small>
</Link>
<Link className="tile" to="/kanban">
{ICONS.kanban}
<strong>Kanban</strong>
<small>Gemeinsame Aufgaben</small>
</Link>
<Link className="tile" to="/monitoring">
{ICONS.monitoring}
<strong>Server-Monitoring</strong>
<small>Status meiner Server</small>
</Link>
</div>
</section>
<LinksDialog ref={dialog} />
</>
);
}