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:
108
app/sign-in/page.tsx
Normal file
108
app/sign-in/page.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
"use client";
|
||||
|
||||
import { FormEvent, useEffect, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useAccount } from "@/contexts/AccountContext";
|
||||
|
||||
export default function SignInPage() {
|
||||
const router = useRouter();
|
||||
const { user, hydrated, signIn } = useAccount();
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [busy, setBusy] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (hydrated && user) router.replace("/dashboard");
|
||||
}, [hydrated, user, router]);
|
||||
|
||||
const onSubmit = async (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError(null);
|
||||
setBusy(true);
|
||||
const res = await signIn(username, password);
|
||||
setBusy(false);
|
||||
if (!res.ok) {
|
||||
setError(res.error);
|
||||
return;
|
||||
}
|
||||
router.push("/dashboard");
|
||||
};
|
||||
|
||||
if (!hydrated || user) {
|
||||
return (
|
||||
<div className="flex min-h-[50vh] items-center justify-center font-mono text-sm text-zinc-500">
|
||||
Loading…
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#0a0a0a] px-4 py-16 text-zinc-200">
|
||||
<div className="mx-auto max-w-md">
|
||||
<p className="font-mono text-[10px] uppercase tracking-[0.35em] text-neon-cyan/80">session</p>
|
||||
<h1 className="mt-3 font-orbitron text-3xl font-bold">Sign in</h1>
|
||||
<p className="mt-3 text-sm text-zinc-500">
|
||||
Client-side vault unlock — your handle ties together forum posts, listings, and checkout history on{" "}
|
||||
<span className="text-zinc-400">this device</span>. Use a unique passphrase; staff never log access to
|
||||
your secrets.
|
||||
</p>
|
||||
<p className="mt-3 text-sm text-zinc-500">
|
||||
Using a different .onion host?{" "}
|
||||
<Link href="/account/hidden-services" className="text-neon-cyan hover:underline">
|
||||
Register or import on every mirror
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
|
||||
<form onSubmit={onSubmit} className="glass mt-10 space-y-5 rounded-2xl border border-white/10 p-8">
|
||||
{error ? (
|
||||
<p className="rounded-lg border border-red-500/40 bg-red-500/10 px-4 py-2 text-sm text-red-300">{error}</p>
|
||||
) : null}
|
||||
<div>
|
||||
<label className="mb-2 block text-xs font-medium text-zinc-400">Handle</label>
|
||||
<input
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
autoComplete="username"
|
||||
required
|
||||
className="glass w-full rounded-xl border border-white/10 bg-transparent px-4 py-3 font-mono text-sm"
|
||||
placeholder="your_alias"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="mb-2 block text-xs font-medium text-zinc-400">Passphrase</label>
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
autoComplete="current-password"
|
||||
required
|
||||
className="glass w-full rounded-xl border border-white/10 bg-transparent px-4 py-3 font-mono text-sm"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={busy}
|
||||
className="w-full rounded-xl bg-gradient-to-r from-neon-cyan to-neon-purple py-3 font-bold text-background disabled:opacity-50"
|
||||
>
|
||||
{busy ? "Unlocking…" : "Unlock dashboard"}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<p className="mt-8 text-center text-sm text-zinc-500">
|
||||
Need an identity?{" "}
|
||||
<Link href="/sign-up" className="text-neon-cyan hover:underline">
|
||||
Create account
|
||||
</Link>
|
||||
</p>
|
||||
<p className="mt-6 text-center">
|
||||
<Link href="/" className="text-xs text-zinc-600 hover:text-zinc-400">
|
||||
← Hub
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user