feat(admin-web): add Taste Skill spike route

This commit is contained in:
root 2026-07-14 23:48:01 +00:00
parent 11f609eb3d
commit ea3f9565bb

View File

@ -0,0 +1,224 @@
import Link from 'next/link';
import {
Activity,
ArrowRight,
CheckCircle2,
Gauge,
Layers3,
ShieldCheck,
Sparkles,
TimerReset,
} from 'lucide-react';
type Mode = 'before' | 'after';
const genericCards = [
['AI insights', 'Powerful dashboards with smart automation for every team.'],
['Fast workflows', 'Streamline productivity with an intuitive modern interface.'],
['Better analytics', 'Unlock value from your data with beautiful charts.'],
];
const healthSignals = [
{ label: 'Tenant isolation', value: '98', tone: 'bg-emerald-500' },
{ label: 'Replay safety', value: '91', tone: 'bg-cyan-500' },
{ label: 'Queue pressure', value: '23', tone: 'bg-amber-500' },
];
const incidents = [
['07:42', 'Digest queue recovered after backoff', 'Auto-remediated'],
['06:10', 'One webhook endpoint has 429 drift', 'Watch'],
['02:55', 'Nightly tenant export completed', 'Verified'],
];
function BeforeSpike() {
return (
<main className="min-h-screen bg-gradient-to-br from-violet-950 via-slate-950 to-blue-950 px-6 py-10 text-white">
<section className="mx-auto flex max-w-6xl flex-col items-center justify-center gap-8 py-20 text-center">
<div className="rounded-full border border-white/20 bg-white/10 px-4 py-1 text-sm backdrop-blur">
AI-powered dashboard
</div>
<div className="space-y-5">
<h1 className="mx-auto max-w-4xl text-5xl font-bold tracking-tight md:text-7xl">
Transform your business with intelligent insights
</h1>
<p className="mx-auto max-w-2xl text-lg text-white/70">
A generic centered hero, purple-blue gradient, and three equal cards. This is the
baseline slop pattern the redesign skill flags.
</p>
</div>
<div className="flex flex-wrap justify-center gap-3">
<Link
href="/taste-spike?mode=after"
className="rounded-full bg-white px-6 py-3 font-semibold text-slate-950"
>
View refined version
</Link>
<button className="rounded-full border border-white/25 px-6 py-3 text-white/80">
Learn more
</button>
</div>
</section>
<section className="mx-auto grid max-w-6xl gap-4 md:grid-cols-3">
{genericCards.map(([title, description]) => (
<article
key={title}
className="rounded-3xl border border-white/10 bg-white/10 p-8 shadow-2xl"
>
<Sparkles className="mb-6 h-8 w-8 text-violet-200" aria-hidden />
<h2 className="text-2xl font-bold">{title}</h2>
<p className="mt-3 text-sm leading-6 text-white/65">{description}</p>
</article>
))}
</section>
</main>
);
}
function AfterSpike() {
return (
<main className="min-h-screen overflow-hidden bg-[#f4f1ea] text-[#17201b]">
<section className="relative mx-auto grid max-w-7xl gap-10 px-6 py-8 md:grid-cols-[0.92fr_1.08fr] md:px-10 lg:px-12">
<div className="absolute inset-x-0 top-0 -z-10 h-80 bg-[radial-gradient(circle_at_20%_20%,rgba(58,93,80,0.22),transparent_32%),radial-gradient(circle_at_82%_8%,rgba(182,122,65,0.2),transparent_28%)]" />
<div className="flex min-h-[720px] flex-col justify-between rounded-[2rem] border border-[#17201b]/10 bg-[#fcfaf5]/85 p-8 shadow-[0_24px_80px_rgba(23,32,27,0.12)] backdrop-blur md:p-10">
<div className="space-y-9">
<div className="flex items-center justify-between gap-4 text-xs uppercase tracking-[0.28em] text-[#6e756c]">
<span>ByteLyst ops taste spike</span>
<span className="font-mono">VAR 5 / MOT 3 / DEN 7</span>
</div>
<div className="space-y-6">
<h1 className="max-w-3xl text-balance text-5xl font-semibold leading-[0.92] tracking-[-0.055em] md:text-7xl">
Product health, but with an operator&apos;s pulse.
</h1>
<p className="max-w-xl text-pretty text-lg leading-8 text-[#556057]">
Reading this as a ByteLyst admin-web dashboard slice for a solo operator, with a
trust-first command-center language, leaning toward Tailwind utilities, warm
surfaces, tabular numerics, and restrained motion.
</p>
</div>
</div>
<div className="grid gap-3 text-sm sm:grid-cols-3">
{healthSignals.map(signal => (
<div
key={signal.label}
className="rounded-2xl border border-[#17201b]/10 bg-white/70 p-4"
>
<div className="mb-4 h-1.5 overflow-hidden rounded-full bg-[#17201b]/10">
<div
className={`h-full rounded-full ${signal.tone}`}
style={{ width: `${signal.value}%` }}
/>
</div>
<div className="font-mono text-3xl font-semibold tabular-nums">{signal.value}</div>
<div className="mt-1 text-[#667066]">{signal.label}</div>
</div>
))}
</div>
</div>
<div className="space-y-5 pt-10 md:pt-28">
<div className="grid gap-5 lg:grid-cols-[0.72fr_1fr]">
<article className="rounded-[1.7rem] border border-[#17201b]/10 bg-[#16211b] p-6 text-[#f4f1ea] shadow-[0_20px_60px_rgba(22,33,27,0.24)]">
<div className="flex items-center justify-between">
<Gauge className="h-6 w-6 text-[#b9d8c5]" aria-hidden />
<span className="rounded-full bg-[#f4f1ea]/10 px-3 py-1 font-mono text-xs text-[#cbd5cd]">
live
</span>
</div>
<div className="mt-16 font-mono text-7xl font-semibold tracking-[-0.08em] tabular-nums">
86
</div>
<p className="mt-3 max-w-48 text-sm leading-6 text-[#cbd5cd]">
Aggregate health score, weighted toward retention and runtime stability.
</p>
</article>
<article className="rounded-[1.7rem] border border-[#17201b]/10 bg-white/80 p-6 shadow-[0_20px_60px_rgba(23,32,27,0.08)]">
<div className="flex items-start justify-between gap-4">
<div>
<p className="text-sm font-medium text-[#6e756c]">Today&apos;s operator brief</p>
<h2 className="mt-2 text-3xl font-semibold tracking-[-0.04em]">
Three signals need eyes.
</h2>
</div>
<Activity className="h-6 w-6 text-[#3f6b5a]" aria-hidden />
</div>
<div className="mt-8 space-y-3">
{incidents.map(([time, item, state]) => (
<div
key={item}
className="grid grid-cols-[4rem_1fr_auto] items-center gap-3 rounded-2xl bg-[#f4f1ea] px-4 py-3 text-sm"
>
<span className="font-mono text-[#6e756c]">{time}</span>
<span className="font-medium">{item}</span>
<span className="rounded-full bg-[#17201b]/5 px-2.5 py-1 text-xs text-[#556057]">
{state}
</span>
</div>
))}
</div>
</article>
</div>
<div className="grid gap-5 lg:grid-cols-3">
{[
[
ShieldCheck,
'Trust surface',
'No neon AI gradient; warm neutrals keep admin tasks calm.',
],
[
Layers3,
'Density tuned',
'Cards carry more information without collapsing into a spreadsheet.',
],
[
TimerReset,
'Motion-safe',
'Only hover/entrance affordances; reduced-motion users keep a static view.',
],
].map(([Icon, title, copy]) => (
<article
key={title as string}
className="group rounded-[1.4rem] border border-[#17201b]/10 bg-[#fcfaf5]/80 p-5 transition-transform motion-safe:hover:-translate-y-1"
>
<Icon className="h-5 w-5 text-[#3f6b5a]" aria-hidden />
<h3 className="mt-8 text-lg font-semibold tracking-[-0.02em]">{title as string}</h3>
<p className="mt-2 text-sm leading-6 text-[#667066]">{copy as string}</p>
</article>
))}
</div>
<div className="flex flex-wrap items-center justify-between gap-4 rounded-[1.7rem] border border-[#17201b]/10 bg-[#dfe8dc] p-5">
<div className="flex items-center gap-3">
<CheckCircle2 className="h-5 w-5 text-[#3f6b5a]" aria-hidden />
<p className="font-medium">
Recommendation: keep as an optional redesign prompt, not a default dashboard
generator.
</p>
</div>
<Link
href="/taste-spike?mode=before"
className="inline-flex items-center gap-2 rounded-full bg-[#17201b] px-4 py-2 text-sm font-semibold text-[#f4f1ea]"
>
Compare baseline <ArrowRight className="h-4 w-4" aria-hidden />
</Link>
</div>
</div>
</section>
</main>
);
}
export default async function TasteSpikePage({
searchParams,
}: {
searchParams?: Promise<{ mode?: string }>;
}) {
const params = await searchParams;
const mode: Mode = params?.mode === 'before' ? 'before' : 'after';
return mode === 'before' ? <BeforeSpike /> : <AfterSpike />;
}