Add persistent onion key backup and restore, improve startup resilience, and flesh out the major site verticals with richer navigation, search coverage, and operator documentation. Made-with: Cursor
168 lines
7.4 KiB
TypeScript
168 lines
7.4 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import LexiconStrip from "@/components/site/LexiconStrip";
|
|
import { useAccount } from "@/contexts/AccountContext";
|
|
import { FORUM_RINGS, getRing } from "@/lib/forumRings";
|
|
import { FORUM_ATMOSPHERE_TAGS } from "@/lib/cyberluxZoneLexicon";
|
|
|
|
const SITE_NAME = "Void Aggregate";
|
|
const SITE_TAGLINE = "distributed rumor ledger";
|
|
|
|
function Scanlines() {
|
|
return (
|
|
<div
|
|
className="pointer-events-none fixed inset-0 z-0 opacity-[0.1]"
|
|
style={{
|
|
backgroundImage:
|
|
"repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,0,0,0.5) 3px)",
|
|
}}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default function ForumSiteChrome({ children }: { children: React.ReactNode }) {
|
|
const { user, hydrated } = useAccount();
|
|
const pathname = usePathname();
|
|
const ringMatch = pathname?.match(/^\/forum\/ring\/([^/]+)/);
|
|
const activeSlug = ringMatch?.[1] ?? null;
|
|
const activeRing = activeSlug ? getRing(activeSlug) : null;
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[#070604] text-[#e7d9c8]">
|
|
<Scanlines />
|
|
<header className="sticky top-0 z-20 border-b border-[#c45c26]/30 bg-[#0d0a07]/95 backdrop-blur-md">
|
|
<div className="mx-auto flex max-w-6xl flex-col gap-3 px-4 py-4 md:flex-row md:items-center md:justify-between">
|
|
<Link href="/forum" className="group block">
|
|
<p className="text-[9px] font-mono uppercase tracking-[0.45em] text-[#ff9a3c]/70">{SITE_TAGLINE}</p>
|
|
<h1 className="font-mono text-xl font-black tracking-tight text-[#ffcb8a] md:text-2xl">
|
|
{SITE_NAME}
|
|
<span className="ml-2 text-[10px] font-normal opacity-50 group-hover:opacity-80">v3</span>
|
|
</h1>
|
|
</Link>
|
|
<div className="flex flex-wrap items-center gap-2 text-[11px] font-mono uppercase tracking-wider">
|
|
<span className="hidden rounded border border-[#5c4030] bg-[#1a1510] px-3 py-1.5 text-[#b8a995] sm:inline">
|
|
onion forum
|
|
</span>
|
|
<Link
|
|
href="/forum/submit"
|
|
className="rounded border border-[#ff9a3c] bg-[#ff9a3c]/15 px-3 py-1.5 font-bold text-[#ffcb8a] hover:bg-[#ff9a3c]/25"
|
|
>
|
|
+ Submit
|
|
</Link>
|
|
{hydrated && user ? (
|
|
<Link href="/dashboard" className="rounded border border-[#2a1810] px-3 py-1.5 text-[#c4a574] hover:border-[#ff9a3c]/45">
|
|
Dashboard
|
|
</Link>
|
|
) : (
|
|
<>
|
|
<Link href="/sign-in" className="rounded border border-[#5c4030] px-3 py-1.5 text-[#c4b5a0] hover:border-[#ff9a3c]/50">
|
|
Sign in
|
|
</Link>
|
|
<Link
|
|
href="/sign-up"
|
|
className="rounded border border-[#ff9a3c]/50 bg-[#ff9a3c]/10 px-3 py-1.5 text-[#ffcb8a] hover:bg-[#ff9a3c]/20"
|
|
>
|
|
Sign up
|
|
</Link>
|
|
<Link
|
|
href="/account/hidden-services"
|
|
className="rounded border border-[#5c4030] px-3 py-1.5 text-[#9a8f7d] hover:border-[#ff9a3c]/50"
|
|
>
|
|
Mirrors
|
|
</Link>
|
|
</>
|
|
)}
|
|
<Link href="/" className="rounded border border-[#5c4030] px-3 py-1.5 text-[#c4b5a0] hover:border-[#ff9a3c]/50">
|
|
Hub
|
|
</Link>
|
|
<Link href="/exchange" className="rounded border border-[#5c4030] px-3 py-1.5 text-[#c4b5a0] hover:border-[#ff9a3c]/50">
|
|
Exchange
|
|
</Link>
|
|
<Link href="/barter" className="rounded border border-[#1a3d24] bg-[#0a120d] px-3 py-1.5 text-[#7cfc9a] hover:border-[#39ff14]/40">
|
|
Barter
|
|
</Link>
|
|
<Link href="/hidden-wiki" className="rounded border border-[#5c4030] px-3 py-1.5 text-[#c4b5a0] hover:border-[#ff9a3c]/50">
|
|
Wiki
|
|
</Link>
|
|
<Link
|
|
href="/darknet-atlas"
|
|
className="rounded border border-[#1e3a5f] bg-[#0a1520] px-3 py-1.5 text-[#7eb8ff] hover:border-[#38bdf8]/50"
|
|
>
|
|
Atlas
|
|
</Link>
|
|
<Link
|
|
href="/search"
|
|
className="rounded border border-[#0d2818] bg-[#050a07] px-3 py-1.5 text-[#6bdc8e] hover:border-[#00ff41]/35"
|
|
>
|
|
Crawler
|
|
</Link>
|
|
<Link href="/chatter" className="rounded border border-[#5c4030] px-3 py-1.5 text-[#c4b5a0] hover:border-[#ff9a3c]/50">
|
|
Hub chatter
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
<div className="mx-auto flex max-w-6xl flex-wrap items-center gap-2 border-t border-[#2a2218] px-4 py-2 text-[10px] font-mono text-[#8a7d6b]">
|
|
<span className="uppercase tracking-widest text-[#c45c26]/90">Depth</span>
|
|
<Link
|
|
href="/forum/handbook"
|
|
className={`rounded px-2 py-0.5 ${pathname?.startsWith("/forum/handbook") ? "bg-[#ff9a3c]/20 text-[#ffcb8a]" : "hover:text-[#ffcb8a]"}`}
|
|
>
|
|
handbook
|
|
</Link>
|
|
<Link
|
|
href="/forum/moderation"
|
|
className={`rounded px-2 py-0.5 ${pathname?.startsWith("/forum/moderation") ? "bg-[#ff9a3c]/20 text-[#ffcb8a]" : "hover:text-[#ffcb8a]"}`}
|
|
>
|
|
moderation
|
|
</Link>
|
|
<Link
|
|
href="/forum/reputation"
|
|
className={`rounded px-2 py-0.5 ${pathname?.startsWith("/forum/reputation") ? "bg-[#ff9a3c]/20 text-[#ffcb8a]" : "hover:text-[#ffcb8a]"}`}
|
|
>
|
|
reputation
|
|
</Link>
|
|
<span className="mx-1 hidden text-[#3d3228] sm:inline">|</span>
|
|
<span className="uppercase tracking-widest text-[#ff9a3c]/80">Rings</span>
|
|
<Link
|
|
href="/forum"
|
|
className={`rounded px-2 py-0.5 ${!activeSlug && pathname === "/forum" ? "bg-[#ff9a3c]/20 text-[#ffcb8a]" : "hover:text-[#ffcb8a]"}`}
|
|
>
|
|
front page
|
|
</Link>
|
|
{FORUM_RINGS.map((r) => (
|
|
<Link
|
|
key={r.slug}
|
|
href={`/forum/ring/${r.slug}`}
|
|
className={`rounded px-2 py-0.5 ${activeSlug === r.slug ? "bg-[#c45c26]/35 text-[#ffcb8a]" : "hover:text-[#ffcb8a]"}`}
|
|
>
|
|
r/{r.shortName}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
<div className="mx-auto max-w-6xl border-t border-[#2a2218] px-4 text-[#6b5c4d]">
|
|
<LexiconStrip label="Board environment · signal lexicon" tags={FORUM_ATMOSPHERE_TAGS} className="border-[#3d3228]" />
|
|
</div>
|
|
</header>
|
|
|
|
<div className="relative z-10 mx-auto max-w-6xl px-4 py-8">
|
|
{activeRing ? (
|
|
<div className="mb-8 rounded-lg border border-[#3d3228] bg-[#120e0a]/90 p-5">
|
|
<p className="font-mono text-[10px] uppercase tracking-[0.3em] text-[#ff9a3c]/70">
|
|
r/{activeRing.shortName}
|
|
</p>
|
|
<h2 className="mt-1 font-mono text-lg font-bold text-[#ffcb8a]">{activeRing.title}</h2>
|
|
<p className="mt-2 max-w-3xl text-sm leading-relaxed text-[#b8a995]">{activeRing.about}</p>
|
|
<div className="mt-4 flex flex-wrap gap-4 font-mono text-[11px] text-[#8a7d6b]">
|
|
<span>{activeRing.members.toLocaleString()} subscribers</span>
|
|
<span>{activeRing.activeNow.toLocaleString()} reading now</span>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
{children}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|