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
102 lines
3.5 KiB
TypeScript
102 lines
3.5 KiB
TypeScript
"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>
|
|
);
|
|
}
|