Patchpass V1
Deploy / Build (push) Successful in 28s
Deploy / Test & Lint (push) Failing after 29s
Deploy / Build and Push Docker Image (push) Has been skipped

This commit is contained in:
Space-Banane
2026-07-18 20:14:44 +02:00
commit 7e05dd918c
101 changed files with 15183 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
import { ReactNode, useState } from "react";
import { Link, NavLink, useNavigate } from "react-router-dom";
import { useAuth } from "../context/AuthContext";
import { NotificationBell } from "./NotificationBell";
const navItems = [
{ to: "/", label: "Dashboard", end: true },
{ to: "/requests", label: "Requests" },
{ to: "/agents", label: "Agents" },
{ to: "/settings", label: "Settings" },
];
export function Layout({ children }: { children: ReactNode }) {
const { user, logout } = useAuth();
const navigate = useNavigate();
const [menuOpen, setMenuOpen] = useState(false);
return (
<div className="min-h-screen">
<header className="sticky top-0 z-30 border-b border-border bg-bg/80 backdrop-blur">
<div className="mx-auto flex max-w-6xl items-center justify-between px-4 py-3">
<div className="flex items-center gap-6">
<Link to="/" className="flex items-center gap-2">
<span className="text-xl"></span>
<span className="text-lg font-bold tracking-tight">
Patch<span className="text-primary">Pass</span>
</span>
</Link>
<nav className="hidden items-center gap-1 md:flex">
{navItems.map((item) => (
<NavLink
key={item.to}
to={item.to}
end={item.end}
className={({ isActive }) =>
`rounded-lg px-3 py-1.5 text-sm font-medium transition ${
isActive ? "bg-surface-raised text-text" : "text-muted hover:text-text"
}`
}
>
{item.label}
</NavLink>
))}
{user?.role === "ADMIN" && (
<NavLink
to="/admin"
className={({ isActive }) =>
`rounded-lg px-3 py-1.5 text-sm font-medium transition ${
isActive ? "bg-surface-raised text-accent" : "text-accent/70 hover:text-accent"
}`
}
>
Admin
</NavLink>
)}
</nav>
</div>
<div className="flex items-center gap-2">
<NotificationBell />
<div className="relative">
<button
onClick={() => setMenuOpen((o) => !o)}
className="flex items-center gap-2 rounded-lg px-2 py-1.5 text-sm hover:bg-surface-raised"
>
<span className="flex h-7 w-7 items-center justify-center rounded-full bg-primary-dim/50 text-xs font-semibold text-primary">
{user?.display_name?.[0]?.toUpperCase()}
</span>
<span className="hidden text-text sm:inline">{user?.display_name}</span>
</button>
{menuOpen && (
<div
className="animate-fade-in absolute right-0 mt-2 w-44 rounded-xl border border-border-strong bg-surface py-1 shadow-2xl"
onMouseLeave={() => setMenuOpen(false)}
>
<Link
to="/settings"
className="block px-4 py-2 text-sm text-muted hover:bg-surface-raised hover:text-text"
onClick={() => setMenuOpen(false)}
>
Settings
</Link>
<Link
to="/notifications"
className="block px-4 py-2 text-sm text-muted hover:bg-surface-raised hover:text-text md:hidden"
onClick={() => setMenuOpen(false)}
>
Notifications
</Link>
<button
onClick={async () => {
await logout();
navigate("/login");
}}
className="block w-full px-4 py-2 text-left text-sm text-rejected hover:bg-surface-raised"
>
Log out
</button>
</div>
)}
</div>
</div>
</div>
{/* mobile nav */}
<nav className="flex items-center gap-1 overflow-x-auto border-t border-border px-4 py-2 md:hidden">
{navItems.map((item) => (
<NavLink
key={item.to}
to={item.to}
end={item.end}
className={({ isActive }) =>
`whitespace-nowrap rounded-lg px-3 py-1.5 text-sm font-medium ${
isActive ? "bg-surface-raised text-text" : "text-muted"
}`
}
>
{item.label}
</NavLink>
))}
{user?.role === "ADMIN" && (
<NavLink to="/admin" className="whitespace-nowrap rounded-lg px-3 py-1.5 text-sm text-accent">
Admin
</NavLink>
)}
</nav>
</header>
<main className="mx-auto max-w-6xl px-4 py-8">{children}</main>
<footer className="mx-auto max-w-6xl px-4 py-8 text-center text-xs text-faint">
<div className="flex flex-wrap items-center justify-center gap-3">
<Link to="/privacy" className="hover:text-muted">
Privacy Policy
</Link>
<span>·</span>
<Link to="/terms" className="hover:text-muted">
Terms of Service
</Link>
<span>·</span>
<span>PatchPass review changes, approve intent, let agents proceed.</span>
</div>
</footer>
</div>
);
}