Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 73 additions & 39 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,73 @@
import Link from "next/link";

const links = [
{ href: "/", label: "Home" },
{ href: "/pairs", label: "Pairs" },
{ href: "/quote", label: "Quote" },
{ href: "/stats", label: "Stats" },
{ href: "/admin", label: "Admin" },
];

export function Header() {
return (
<header className="border-b border-neutral-200 dark:border-neutral-800">
<nav
aria-label="Main navigation"
className="mx-auto flex max-w-5xl items-center justify-between p-4"
>
<Link
href="/"
className="text-lg font-semibold focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500"
>
StableRoute
</Link>
<ul className="flex gap-4 text-sm">
{links.map((l) => (
<li key={l.href}>
<Link
href={l.href}
className="rounded px-2 py-1 hover:bg-neutral-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 dark:hover:bg-neutral-800"
>
{l.label}
</Link>
</li>
))}
</ul>
</nav>
</header>
);
}
"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";
import { useState } from "react";
import { ThemeToggle } from "@/components/ThemeToggle";
import { ROUTES } from "@/lib/routes";

const navLinks = [
ROUTES.home,
ROUTES.pairs,
ROUTES.quote,
ROUTES.stats,
ROUTES.admin,
ROUTES.events,
ROUTES.webhooks,
ROUTES.apiKeys,
ROUTES.settings,
ROUTES.docs,
];

export function Header() {
const pathname = usePathname();
const [mobileOpen, setMobileOpen] = useState(false);

return (
<header className="border-b border-neutral-200 dark:border-neutral-800">
<div className="mx-auto flex max-w-5xl items-center justify-between gap-3 p-4">
<Link
href="/"
className="text-lg font-semibold focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500"
>
StableRoute
</Link>
<div className="flex items-center gap-2">
<ThemeToggle />
<button
type="button"
className="rounded border border-neutral-300 px-3 py-1 text-sm md:hidden dark:border-neutral-700"
aria-expanded={mobileOpen}
aria-controls="main-nav"
onClick={() => setMobileOpen((open) => !open)}
>
{mobileOpen ? "Close" : "Menu"}
</button>
</div>
</div>
<nav
id="main-nav"
aria-label="Main navigation"
className={`mx-auto max-w-5xl px-4 pb-4 ${mobileOpen ? "block" : "hidden md:block"}`}
>
<ul className="flex flex-col gap-1 md:flex-row md:flex-wrap md:gap-3 md:text-sm">
{navLinks.map((link) => {
const active = pathname === link.href;
return (
<li key={link.href}>
<Link
href={link.href}
aria-current={active ? "page" : undefined}
className="block rounded px-2 py-1 hover:bg-neutral-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 dark:hover:bg-neutral-800"
onClick={() => setMobileOpen(false)}
>
{link.title}
</Link>
</li>
);
})}
</ul>
</nav>
</header>
);
}
12 changes: 12 additions & 0 deletions src/lib/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const ROUTES = {
home: { href: "/", title: "Home", description: "StableRoute dashboard landing page." },
pairs: { href: "/pairs", title: "Pairs", description: "Manage registered routing pairs." },
quote: { href: "/quote", title: "Quote", description: "Request routing quotes." },
stats: { href: "/stats", title: "Stats", description: "View router metrics." },
admin: { href: "/admin", title: "Admin", description: "Pause or resume the router." },
events: { href: "/events", title: "Events", description: "Inspect router event log." },
webhooks: { href: "/webhooks", title: "Webhooks", description: "Register webhook endpoints." },
apiKeys: { href: "/api-keys", title: "API keys", description: "Manage operator API keys." },
settings: { href: "/settings", title: "Settings", description: "Appearance and API configuration." },
docs: { href: "/docs", title: "Docs", description: "HTTP API reference." },
} as const;