Files
dark-lord/app/mixer/page.tsx
drjones 78a071ba02 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
2026-04-07 21:35:52 -07:00

174 lines
7.5 KiB
TypeScript

"use client";
import { useMemo, useState } from "react";
import ThemedLayout from "@/components/layouts/ThemedLayout";
import { useWallet } from "@/contexts/WalletContext";
type MixLog = { id: string; text: string };
function id() {
return Math.random().toString(16).slice(2, 10).toUpperCase();
}
export default function MixerPage() {
const { isConnected, luxCredits, spendLuxCredits, setVaultFlag, addVaultReceipt } = useWallet();
const [amount, setAmount] = useState(500);
const [hops, setHops] = useState(3);
const [noise, setNoise] = useState(65);
const [log, setLog] = useState<MixLog[]>([]);
const fee = useMemo(() => {
const base = Math.floor(amount * 0.04);
const hopFee = hops * 25;
const noiseFee = Math.floor(noise * 2);
return base + hopFee + noiseFee;
}, [amount, hops, noise]);
const total = amount + fee;
const push = (text: string) => setLog((l) => [{ id: id(), text }, ...l].slice(0, 10));
return (
<ThemedLayout theme="terminal" siteTitle="COIN BLENDER" siteSubtitle="Parody mixer simulator">
<section className="container mx-auto max-w-6xl px-4 py-12">
<div className="text-center">
<h1 className="text-4xl font-bold md:text-5xl">
COIN <span className="theme-accent">BLENDER</span>
</h1>
<p className="mx-auto mt-6 max-w-3xl text-xl opacity-90">
All the bells, all the whistles, zero real-world functionality.
</p>
<p className="mx-auto mt-3 max-w-3xl text-sm opacity-70">
Parody simulator: this does not mix real crypto, does not provide laundering tools, and never accepts deposits.
It only burns your in-game LUX credits in a dramatic way.
</p>
</div>
<div className="mt-12 grid grid-cols-1 gap-8 lg:grid-cols-3">
<div className="theme-card rounded-3xl border border-white/10 p-8 lg:col-span-2">
<div className="mb-6 flex items-end justify-between gap-4">
<div>
<div className="text-xs text-foreground/40">available</div>
<div className="font-orbitron text-4xl font-bold text-neon-green">
{luxCredits.toLocaleString()} LUX
</div>
</div>
<div className="text-right text-sm text-foreground/60">
{isConnected ? "Wallet connected (mock)" : "Connect wallet to enable the blender"}
</div>
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
<div className="theme-card rounded-2xl border border-white/10 p-6">
<div className="font-bold mb-2">Amount (LUX)</div>
<input
type="range"
min={50}
max={2500}
value={amount}
onChange={(e) => setAmount(parseInt(e.target.value, 10))}
className="w-full"
disabled={!isConnected}
/>
<div className="mt-2 text-foreground/70">{amount.toLocaleString()} LUX</div>
<div className="mt-6 font-bold mb-2">Route hops</div>
<div className="grid grid-cols-5 gap-2">
{[1, 2, 3, 4, 5].map((n) => (
<button
key={n}
disabled={!isConnected}
onClick={() => setHops(n)}
className={`rounded-xl border px-3 py-2 text-sm font-bold ${
hops === n ? "border-neon-cyan bg-neon-cyan/10" : "border-white/10 bg-white/5"
}`}
>
{n}
</button>
))}
</div>
<div className="mt-6 font-bold mb-2">Plausible deniability noise</div>
<input
type="range"
min={0}
max={100}
value={noise}
onChange={(e) => setNoise(parseInt(e.target.value, 10))}
className="w-full"
disabled={!isConnected}
/>
<div className="mt-2 text-foreground/70">{noise}% nonsense</div>
</div>
<div className="theme-card rounded-2xl border border-white/10 p-6">
<div className="font-orbitron text-2xl font-bold mb-4">Receipt</div>
<div className="space-y-3 text-sm text-foreground/70">
<div className="flex justify-between">
<span>Blend amount</span>
<span className="font-bold">{amount.toLocaleString()} LUX</span>
</div>
<div className="flex justify-between">
<span>Obfuscation fee</span>
<span className="font-bold text-neon-pink">{fee.toLocaleString()} LUX</span>
</div>
<div className="flex justify-between border-t border-white/10 pt-3">
<span>Total burn</span>
<span className="font-orbitron font-bold text-neon-pink">{total.toLocaleString()} LUX</span>
</div>
<div className="mt-4 rounded-xl bg-white/5 p-4 text-xs text-foreground/60">
Advanced features: onion routing animation, entropy fog, decoy receipts, and a fake compliance dashboard.
The only real output is regret.
</div>
</div>
<button
disabled={!isConnected}
className="mt-6 w-full rounded-full bg-gradient-to-r from-neon-purple to-neon-pink px-6 py-3 font-bold text-background disabled:opacity-40"
onClick={() => {
const ok = spendLuxCredits(total);
if (!ok) {
push("Blend failed: insufficient LUX. The blender demands tribute.");
return;
}
setVaultFlag("blendedOnce", true);
addVaultReceipt({
id: `MX-${id()}`,
title: "Blender Session Log",
desc: `Receipt generated: ${amount.toLocaleString()} LUX blended with ${noise}% noise across ${hops} hops. Output: 0 LUX. Privacy achieved. Regret maximized.`,
date: new Date().toISOString().slice(0, 10),
severity: "redacted",
});
push(`Session ${id()}: accepted. Injecting ${noise}% noise…`);
push(`Session ${id()}: routing through ${hops} hops…`);
push(`Session ${id()}: generating decoy receipts…`);
push(`Session ${id()}: complete. Output: 0 LUX (privacy achieved).`);
}}
>
BLEND NOW 🌀
</button>
</div>
</div>
</div>
<div className="theme-card rounded-3xl border border-white/10 p-8">
<div className="font-orbitron text-2xl font-bold">Console</div>
<div className="mt-6 space-y-3">
{log.length === 0 ? (
<div className="text-foreground/60">No sessions yet. The blender is bored.</div>
) : (
log.map((e) => (
<div key={e.id} className="rounded-xl bg-black/40 border border-white/10 p-4 font-mono text-xs text-neon-green">
{e.text}
</div>
))
)}
</div>
</div>
</div>
</section>
</ThemedLayout>
);
}