- AuthBox mit Login/Registrierung (Auto-Login nach Registrierung) - Compose mit Zwischenablage-Bild, Feed springt danach an den Anfang - Headerbar mit Profil-Link und Logout - useAuthChanged: me und Votes nach Login/Logout neu laden - kein Aufblitzen der Login-Box, solange der Anmeldestatus lädt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TiXsPUqw7oeomZ8wZrQW5q
67 lines
2.1 KiB
TypeScript
67 lines
2.1 KiB
TypeScript
import { Link, Outlet, useLocation } from "react-router";
|
|
import { api } from "./api";
|
|
import { useAuthChanged, useMe } from "./auth";
|
|
|
|
// Tage ohne Datenverlust (fester Startpunkt, Kontinuität seit der alten
|
|
// Version).
|
|
const dataLossStart = new Date("2025-12-13T12:44:00").getTime();
|
|
|
|
function plural(n: number, one: string, many: string) {
|
|
return `${n} ${n === 1 ? one : many}`;
|
|
}
|
|
|
|
// Layout ist der gemeinsame Seitenrahmen. Markup und IDs entsprechen dem alten
|
|
// Frontend (web/*.html), damit app.css unverändert greift: die Startseite hat
|
|
// Tagline und Headerbar, alle anderen Seiten den "zurück zum Feed"-Knopf.
|
|
export function Layout() {
|
|
const isHome = useLocation().pathname === "/";
|
|
const days = Math.floor((Date.now() - dataLossStart) / 86400000);
|
|
|
|
return (
|
|
<>
|
|
<header>
|
|
<nav id="legal">
|
|
<a href="/static/docs/impressum.html">Impressum</a> -{" "}
|
|
<a href="/static/docs/datenschutz.html">Datenschutz</a> -{" "}
|
|
<a href="/static/docs/beitragsordnung.html">Beitragsordnung</a> -{" "}
|
|
<Link to="/stats">Statistik</Link>
|
|
</nav>
|
|
<Link to="/"><h1>Kontrollverlust</h1></Link>
|
|
{isHome ? (
|
|
<>
|
|
<p id="stats" className="tagline">
|
|
Ohne Datenverlust seit {plural(days, "Tag", "Tagen")}
|
|
</p>
|
|
<Headerbar />
|
|
</>
|
|
) : (
|
|
<div id="headerbar"><Link className="button" to="/">zurück zum Feed</Link></div>
|
|
)}
|
|
</header>
|
|
|
|
<main>
|
|
<Outlet />
|
|
</main>
|
|
</>
|
|
);
|
|
}
|
|
|
|
// Headerbar der Startseite: angemeldet Profil-Link und Logout, sonst leer.
|
|
function Headerbar() {
|
|
const me = useMe().data;
|
|
const authChanged = useAuthChanged();
|
|
if (!me) return <div id="headerbar"></div>;
|
|
|
|
// POST statt GET: als GET wäre Logout per fremdem Link auslösbar (CSRF).
|
|
const logout = async () => {
|
|
await api.post("/auth/logout").catch(() => undefined);
|
|
await authChanged();
|
|
};
|
|
return (
|
|
<div id="headerbar">
|
|
<Link className="button" to={`/u/${encodeURIComponent(me.username)}`}>mein Profil</Link>{" "}
|
|
<button id="logout-btn" onClick={logout}>Logout</button>
|
|
</div>
|
|
);
|
|
}
|