Really huge mass update; Getting everything up-to-spec and implementing a wide range of features
Deploy / Build (pull_request) Successful in 40s
Deploy / Build and Push Docker Image (pull_request) Has been skipped

This commit is contained in:
2026-07-26 14:24:18 +02:00
parent 2c563685bd
commit 8b53698f29
72 changed files with 4275 additions and 693 deletions
+40 -13
View File
@@ -1,13 +1,19 @@
import React from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { useAuth } from "../hooks/useAuth";
import { useTheme } from "../hooks/useTheme";
import { ThemePreference, useTheme } from "../hooks/useTheme";
import { api } from "../services/api";
import { toast } from "react-toastify";
import { Rocket, Sun, Moon, Monitor } from "lucide-react";
const themeOptions: { value: ThemePreference; label: string; Icon: typeof Sun }[] = [
{ value: "light", label: "Light", Icon: Sun },
{ value: "dark", label: "Dark", Icon: Moon },
{ value: "system", label: "System", Icon: Monitor },
];
export function Layout({ children }: { children: React.ReactNode }) {
const { user, refresh } = useAuth();
const { dark, toggle } = useTheme();
const { theme, setTheme } = useTheme();
const location = useLocation();
const navigate = useNavigate();
@@ -35,14 +41,15 @@ export function Layout({ children }: { children: React.ReactNode }) {
<header className="border-b border-gray-200 dark:border-slate-700 bg-white dark:bg-slate-900 sticky top-0 z-50">
<div className="max-w-7xl mx-auto px-4 h-14 flex items-center justify-between gap-4">
<div className="flex items-center gap-2">
<Link to="/" className="font-bold text-lg text-blue-600 dark:text-blue-400 hover:opacity-80">
🚀 PR Previews
<Link to="/" className="font-bold text-lg text-blue-600 dark:text-blue-400 hover:opacity-80 inline-flex items-center gap-1.5">
<Rocket size={20} /> PR Previews
</Link>
</div>
{user && (
<nav className="flex items-center gap-1 overflow-x-auto">
{navLink("/", "Previews")}
{navLink("/", "Overview")}
{navLink("/previews", "Previews")}
{navLink("/repos", "Repos")}
{navLink("/settings", "Settings")}
{user.isAdmin && navLink("/admin", "Admin")}
@@ -50,13 +57,33 @@ export function Layout({ children }: { children: React.ReactNode }) {
)}
<div className="flex items-center gap-2 shrink-0">
<button
onClick={toggle}
className="p-2 rounded-md hover:bg-gray-100 dark:hover:bg-slate-800 text-lg"
title="Toggle theme"
<div
className="inline-flex items-center rounded-lg border border-gray-200 dark:border-slate-700 bg-gray-50 dark:bg-slate-800 p-1"
role="group"
aria-label="Theme preference"
>
{dark ? "☀️" : "🌙"}
</button>
{themeOptions.map(({ value, label, Icon }) => {
const selected = theme === value;
return (
<button
key={value}
type="button"
onClick={() => setTheme(value)}
aria-label={`${label} theme`}
aria-pressed={selected}
title={`${label} theme`}
className={`inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1 dark:focus-visible:ring-offset-slate-900 ${
selected
? "bg-white dark:bg-slate-700 text-blue-700 dark:text-blue-300 shadow-sm"
: "text-gray-500 dark:text-slate-400 hover:text-gray-900 dark:hover:text-slate-100"
}`}
>
<Icon size={15} aria-hidden="true" />
<span className="hidden lg:inline">{label}</span>
</button>
);
})}
</div>
{user && (
<button
onClick={handleLogout}
@@ -74,7 +101,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
</main>
<footer className="border-t border-gray-200 dark:border-slate-700 py-4 text-center text-xs text-gray-500 dark:text-slate-400">
PR Previews self-hosted preview environments for every pull request.{" "}
PR Previews self-hosted preview environments for every pull request. {" "}
<Link to="/privacy" className="underline hover:text-gray-700 dark:hover:text-slate-200">Privacy Policy</Link>
</footer>
</div>