Harden onion boot flow and deepen site surfaces
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
This commit is contained in:
101
components/forum/ForumFeedToolbar.tsx
Normal file
101
components/forum/ForumFeedToolbar.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import Link from "next/link";
|
||||
import { FORUM_RINGS } from "@/lib/forumRings";
|
||||
import type { ForumSortMode } from "@/lib/forumSort";
|
||||
|
||||
type Props = {
|
||||
sort: ForumSortMode;
|
||||
onSortChange: (m: ForumSortMode) => void;
|
||||
search: string;
|
||||
onSearchChange: (q: string) => void;
|
||||
/** When set, show ring chips + `null` = all rings. Omit `onRingChange` to hide chips (ring sub-page). */
|
||||
ringFilter: string | null;
|
||||
onRingChange?: (slug: string | null) => void;
|
||||
extraRight?: ReactNode;
|
||||
threadCount?: number;
|
||||
hydrated?: boolean;
|
||||
};
|
||||
|
||||
export default function ForumFeedToolbar({
|
||||
sort,
|
||||
onSortChange,
|
||||
search,
|
||||
onSearchChange,
|
||||
ringFilter,
|
||||
onRingChange,
|
||||
extraRight,
|
||||
threadCount,
|
||||
hydrated,
|
||||
}: Props) {
|
||||
return (
|
||||
<div className="space-y-4 border-b border-[#3d3228] pb-4">
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<label className="min-w-0 flex-1 font-mono text-[10px] uppercase tracking-wider text-[#8a7d6b]">
|
||||
<span className="mb-1 block text-[#ff9a3c]/70">Search threads</span>
|
||||
<input
|
||||
value={search}
|
||||
onChange={(e) => onSearchChange(e.target.value)}
|
||||
placeholder="Title, body, author, ring…"
|
||||
className="w-full rounded border border-[#3d3228] bg-[#0d0a07] px-3 py-2 font-mono text-sm text-[#e7d9c8] placeholder:text-[#5c5044] focus:border-[#ff9a3c]/60 focus:outline-none"
|
||||
/>
|
||||
</label>
|
||||
<div className="flex shrink-0 flex-wrap items-center gap-2">
|
||||
{(["hot", "new", "top"] as const).map((m) => (
|
||||
<button
|
||||
key={m}
|
||||
type="button"
|
||||
onClick={() => onSortChange(m)}
|
||||
className={`rounded px-3 py-1.5 font-mono text-[11px] font-bold uppercase tracking-wider ${
|
||||
sort === m ? "bg-[#c45c26]/40 text-[#ffcb8a]" : "text-[#8a7d6b] hover:text-[#ffcb8a]"
|
||||
}`}
|
||||
>
|
||||
{m}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{onRingChange ? (
|
||||
<div className="flex flex-wrap items-center gap-2 font-mono text-[10px] uppercase tracking-wider">
|
||||
<span className="text-[#5c5044]">Ring</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onRingChange(null)}
|
||||
className={`rounded px-2.5 py-1 font-bold ${
|
||||
ringFilter === null ? "bg-[#3d3228] text-[#ffcb8a]" : "text-[#8a7d6b] hover:text-[#ffcb8a]"
|
||||
}`}
|
||||
>
|
||||
all
|
||||
</button>
|
||||
{FORUM_RINGS.map((r) => (
|
||||
<button
|
||||
key={r.slug}
|
||||
type="button"
|
||||
onClick={() => onRingChange(r.slug)}
|
||||
className={`rounded px-2.5 py-1 font-bold ${
|
||||
ringFilter === r.slug ? "bg-[#ff9a3c]/20 text-[#ffcb8a]" : "text-[#8a7d6b] hover:text-[#ffcb8a]"
|
||||
}`}
|
||||
>
|
||||
r/{r.shortName}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="flex flex-wrap items-center justify-between gap-2 font-mono text-[10px] text-[#5c5044]">
|
||||
<span>{hydrated === false ? "…" : threadCount !== undefined ? `${threadCount} threads` : null}</span>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{extraRight}
|
||||
<Link
|
||||
href="/forum/submit"
|
||||
className="rounded border border-[#ff9a3c]/60 px-3 py-1 font-bold uppercase text-[#ffcb8a] hover:bg-[#ff9a3c]/15"
|
||||
>
|
||||
+ New post
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user