GUI ans Mockup-Design angepasst (GEFIM-Branding)

- GEFIM-Farbwelt aus dem Mockup als shadcn-Theme: Violett #5d52a3 als
  Primärfarbe, Magenta/Hellblau-Akzente, Ink-Text, #f5f6fa-Hintergrund,
  Verlaufs-Utilities (bg-grad, bg-grad-soft), Karten-Schatten
- Fonts Poppins (Überschriften/Buttons) + Open Sans (Text), self-hosted
  über next/font — kein Google-CDN-Aufruf zur Laufzeit (DSGVO)
- Sidebar mit extrahiertem GEFIM-Logo (public/gefim-logo.png), aktive
  Navigation in Violett wie im Prototyp
- Sticky Topbar mit globaler Suche (leitet vorerst auf die Asset-Suche),
  Nutzer-Info und Verlaufs-Avatar mit Initialen; Logout in die Topbar
- Primär-Buttons mit Verlaufshintergrund, Level-Badges als Pillen in
  Mockup-Farben, Login-Seite im GEFIM-Look
- Dashboard im Mockup-Stil: KPI-Karten (Assets, Prozesse, kritische
  Prozesse, Risiken-Platzhalter) und Letzte-Aktivitäten-Feed aus dem
  echten Audit-Log

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Martin
2026-07-02 13:51:11 +02:00
co-authored by Claude Fable 5
parent 392bb246cf
commit 0befcc6a2c
13 changed files with 293 additions and 163 deletions
+52 -16
View File
@@ -1,4 +1,5 @@
import Link from "next/link";
import Image from "next/image";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import {
@@ -14,6 +15,7 @@ import {
FolderCheck,
Truck,
LineChart,
Search,
} from "lucide-react";
import { auth, signOut } from "@/server/auth";
import { Button } from "@/components/ui/button";
@@ -43,6 +45,13 @@ export default async function AppLayout({
{ href: "/review", label: t("review"), icon: LineChart, enabled: false },
];
const initials = (session.user.name ?? "?")
.split(/\s+/)
.map((p) => p[0])
.slice(0, 2)
.join("")
.toUpperCase();
async function logout() {
"use server";
await signOut({ redirectTo: "/login" });
@@ -50,42 +59,69 @@ export default async function AppLayout({
return (
<div className="flex min-h-screen">
<aside className="flex w-60 shrink-0 flex-col border-r bg-sidebar">
<div className="flex h-14 items-center border-b px-4">
<Link href="/dashboard" className="font-semibold tracking-tight">
{tc("appName")}
<aside className="flex w-60 shrink-0 flex-col border-r border-sidebar-border bg-sidebar">
<div className="border-b border-sidebar-border px-4 pt-5 pb-3.5">
<Link href="/dashboard">
<Image
src="/gefim-logo.png"
alt="GEFIM — Informationssicherheit im Mittelstand"
width={150}
height={53}
priority
/>
</Link>
</div>
<nav className="flex-1 space-y-0.5 overflow-y-auto p-2">
<nav className="flex-1 space-y-0.5 overflow-y-auto px-2.5 py-3">
{nav.map((item) =>
item.enabled ? (
<NavLink key={item.href} href={item.href} match={item.match}>
<item.icon className="size-4" />
<item.icon className="size-[18px] opacity-85" />
{item.label}
</NavLink>
) : (
<span
key={item.href}
title={tc("comingSoon")}
className="flex cursor-not-allowed items-center gap-2 rounded-md px-3 py-2 text-sm text-muted-foreground/50"
className="flex cursor-not-allowed items-center gap-2.5 rounded-lg px-3 py-2 text-[13.5px] font-semibold text-muted-foreground/50"
>
<item.icon className="size-4" />
<item.icon className="size-[18px]" />
{item.label}
</span>
)
)}
</nav>
<div className="border-t p-3 text-xs text-muted-foreground">
<p className="truncate font-medium text-foreground">{session.user.name}</p>
<p className="truncate">{session.user.tenantSlug}</p>
<form action={logout} className="mt-2">
<Button type="submit" variant="outline" size="sm" className="w-full">
</aside>
<div className="flex min-w-0 flex-1 flex-col">
<header className="sticky top-0 z-10 flex items-center gap-4 border-b bg-white/90 px-6 py-2.5 backdrop-blur-md">
<form
method="GET"
action="/assets"
className="flex w-full max-w-105 items-center gap-2 rounded-lg border bg-muted px-3 py-2 text-muted-foreground"
>
<Search className="size-4 shrink-0" />
<input
name="q"
placeholder={tc("search")}
className="w-full border-0 bg-transparent text-[13px] text-foreground outline-none placeholder:text-muted-foreground"
/>
</form>
<div className="flex-1" />
<div className="text-right leading-tight">
<p className="text-[13px] font-semibold">{session.user.name}</p>
<p className="text-xs text-muted-foreground">{session.user.tenantSlug}</p>
</div>
<div className="bg-grad-soft grid size-9.5 shrink-0 place-items-center rounded-full font-heading text-sm font-bold text-white">
{initials}
</div>
<form action={logout}>
<Button type="submit" variant="ghost" size="sm">
{tc("logout")}
</Button>
</form>
</div>
</aside>
<div className="flex min-w-0 flex-1 flex-col">{children}</div>
</header>
{children}
</div>
</div>
);
}