homepage tweaks

This commit is contained in:
2025-12-28 17:37:02 -05:00
parent 2202abe89f
commit 0dd89a751b
4 changed files with 201 additions and 45 deletions
+181 -45
View File
@@ -3,6 +3,14 @@
import { FormEvent, useState } from "react"; import { FormEvent, useState } from "react";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import {
WrenchScrewdriverIcon,
ShieldExclamationIcon,
CurrencyDollarIcon,
BookmarkSquareIcon,
BuildingStorefrontIcon,
ChatBubbleLeftRightIcon,
} from "@heroicons/react/20/solid";
export default function HomePage() { export default function HomePage() {
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
@@ -39,7 +47,12 @@ export default function HomePage() {
const res = await fetch("/api/beta-signup", { const res = await fetch("/api/beta-signup", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, useCase, acceptedTos: accepted, tosVersion: TOS_VERSION }), body: JSON.stringify({
email,
useCase,
acceptedTos: accepted,
tosVersion: TOS_VERSION,
}),
}); });
if (!res.ok) { if (!res.ok) {
@@ -60,6 +73,43 @@ export default function HomePage() {
} }
} }
const features = [
{
name: "Guided part roles",
description: "Pick parts by role so youre not guessing what fits where.",
icon: WrenchScrewdriverIcon,
},
{
name: "Basic compatibility warnings",
description:
"Early guardrails to catch obvious mismatches before you buy.",
icon: ShieldExclamationIcon,
},
{
name: "Live pricing totals",
description:
"See the running total as you build, with real retailer listings.",
icon: CurrencyDollarIcon,
},
{
name: "Save builds",
description: "Save a build to your account so you can finish it later.",
icon: BookmarkSquareIcon,
},
{
name: "Limited retailers (for now)",
description:
"Were starting small with a couple merchants and expanding fast.",
icon: BuildingStorefrontIcon,
},
{
name: "Feedback-driven roadmap",
description:
"Tell us whats confusing, wrong, or missing — well fix that first.",
icon: ChatBubbleLeftRightIcon,
},
];
return ( return (
<main className="min-h-screen bg-black text-zinc-50"> <main className="min-h-screen bg-black text-zinc-50">
{/* Abstract Brand Background */} {/* Abstract Brand Background */}
@@ -112,48 +162,71 @@ export default function HomePage() {
{/* Top Bar / Logo */} {/* Top Bar / Logo */}
<header className="flex items-center justify-between gap-4"> <header className="flex items-center justify-between gap-4">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="flex items-center"> <Image
<Image src="/battl/battl-logo-mark-f.svg"
src="/battl/battl-logo-mark-f.svg" alt="Battl Builders Logo"
alt="Battl Builders Logo" width={260}
width={260} // adjust to taste height={48}
height={48} // adjust to taste className="block"
className="block" />
/>
</div>
</div> </div>
<span className="rounded-full border border-amber-500/40 bg-amber-500/10 px-3 py-1 text-xs font-medium text-amber-300"> <nav className="flex items-center gap-2 sm:gap-3">
Private Beta Coming Soon <a
</span> href="#request-access"
className="rounded-md border border-zinc-800 bg-zinc-950/60 px-3 py-2 text-xs font-medium text-zinc-200 hover:bg-zinc-900 hover:text-white"
>
Request Access
</a>
<Link
href="/login"
className="rounded-md border border-amber-500/60 bg-amber-500/15 px-3 py-2 text-xs font-medium text-amber-200 hover:bg-amber-500/20"
>
Sign In
</Link>
</nav>
</header> </header>
{/* Hero */} {/* Hero */}
<section className="mt-16 grid gap-10 md:grid-cols-[minmax(0,1.3fr)_minmax(0,1fr)] md:items-center"> <section className="mt-16 grid gap-10 md:grid-cols-[minmax(0,1.25fr)_minmax(0,1fr)] md:items-start">
<div> <div>
<h1 className="text-balance text-3xl font-semibold tracking-tight sm:text-4xl md:text-5xl"> <div className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-black/30 px-3 py-1 text-xs uppercase tracking-[0.25em] text-white/70">
<span className="h-1.5 w-1.5 rounded-full bg-amber-400" />
Private Beta
<span className="text-white/40"></span>
<span className="text-white/60">AR-15 focus</span>
</div>
<h1 className="mt-6 text-balance text-3xl font-semibold tracking-tight sm:text-4xl md:text-5xl">
Stop Guessing. Stop Guessing.
<span className="block text-amber-300 py-0.16em"> <span className="block text-amber-300">Start Building.</span>
Start Building.
</span>
</h1> </h1>
<p className="mt-4 max-w-xl text-sm text-zinc-400 sm:text-base"> <p className="mt-4 max-w-xl text-sm text-zinc-400 sm:text-base">
From part comparisons to full-build matchups, Battl Builders helps Battl Builders helps you plan an AR-15 build faster: choose parts
you find the right components, catch compatibility issues, and by role, get basic compatibility guidance, and compare real
score the best deals all without juggling tabs or spreadsheets. listingswithout juggling tabs or spreadsheets.
</p> </p>
<ul className="mt-6 space-y-2 text-sm text-zinc-300"> <ul className="mt-6 space-y-2 text-sm text-zinc-300">
<li> Side-by-side part & build comparisons</li> <li> Guided part roles (no where does this go?)</li>
<li> Smart compatibility checks</li> <li> Basic compatibility warnings</li>
<li> Live pricing from vetted merchants</li> <li> Live pricing from current retailers</li>
<li> Save & share builds with your crew</li> <li> Save builds to your account</li>
<li> Vote on the cleanest, meanest setups</li>
</ul> </ul>
<p className="mt-4 text-xs text-white/50">
Early access beta. Data, pricing, and available parts are still
evolving.
</p>
</div> </div>
{/* Beta Form */} {/* Beta Form */}
<div className="rounded-lg border border-zinc-800 bg-zinc-950/70 p-5 shadow-[0_0_0_1px_rgba(24,24,27,0.9)]"> <div
id="request-access"
className="scroll-mt-24 rounded-lg border border-zinc-800 bg-zinc-950/70 p-5 shadow-[0_0_0_1px_rgba(24,24,27,0.9)]"
>
<h2 className="text-sm font-semibold uppercase tracking-[0.18em] text-zinc-500"> <h2 className="text-sm font-semibold uppercase tracking-[0.18em] text-zinc-500">
Join the Beta List Join the Beta List
</h2> </h2>
@@ -177,7 +250,7 @@ export default function HomePage() {
onChange={(e) => setEmail(e.target.value)} onChange={(e) => setEmail(e.target.value)}
placeholder="you@gearjunkie.com" placeholder="you@gearjunkie.com"
disabled={status === "loading" || status === "success"} disabled={status === "loading" || status === "success"}
className="mt-1 w-full rounded-md border border-zinc-800 bg-zinc-950 px-3 py-2 text-sm text-zinc-50 outline-none ring-amber-500/30 placeholder:text-zinc-600 focus:border-amber-400/80 focus:ring-2 disabled:opacity-60 disabled:cursor-not-allowed" className="mt-1 w-full rounded-md border border-zinc-800 bg-zinc-950 px-3 py-2 text-sm text-zinc-50 outline-none ring-amber-500/30 placeholder:text-zinc-600 focus:border-amber-400/80 focus:ring-2 disabled:cursor-not-allowed disabled:opacity-60"
required required
/> />
</div> </div>
@@ -196,8 +269,8 @@ export default function HomePage() {
onChange={(e) => setUseCase(e.target.value)} onChange={(e) => setUseCase(e.target.value)}
rows={3} rows={3}
disabled={status === "loading" || status === "success"} disabled={status === "loading" || status === "success"}
placeholder="E.g. Comparing build costs, finding the best deals, sharing my builds, weird influencer shit..." placeholder="E.g. Planning a build, comparing costs, sanity-checking compatibility..."
className="mt-1 w-full rounded-md border border-zinc-800 bg-zinc-950 px-3 py-2 text-xs text-zinc-50 outline-none ring-amber-500/30 placeholder:text-zinc-600 focus:border-amber-400/80 focus:ring-2 disabled:opacity-60 disabled:cursor-not-allowed" className="mt-1 w-full rounded-md border border-zinc-800 bg-zinc-950 px-3 py-2 text-xs text-zinc-50 outline-none ring-amber-500/30 placeholder:text-zinc-600 focus:border-amber-400/80 focus:ring-2 disabled:cursor-not-allowed disabled:opacity-60"
/> />
</div> </div>
@@ -215,14 +288,14 @@ export default function HomePage() {
I agree to the{" "} I agree to the{" "}
<Link <Link
href="/tos" href="/tos"
className="text-amber-300 hover:text-amber-200 underline" className="text-amber-300 underline hover:text-amber-200"
> >
Terms of Service Terms of Service
</Link>{" "} </Link>{" "}
and{" "} and{" "}
<Link <Link
href="/privacy" href="/privacy"
className="text-amber-300 hover:text-amber-200 underline" className="text-amber-300 underline hover:text-amber-200"
> >
Privacy Policy Privacy Policy
</Link> </Link>
@@ -261,19 +334,6 @@ export default function HomePage() {
</p> </p>
)} )}
{status === "success" && (
<button
type="button"
onClick={() => {
setStatus("idle");
setMessage(null);
}}
className="w-full rounded-md border border-zinc-800 bg-zinc-950 px-3 py-2 text-xs text-zinc-200 hover:bg-zinc-900"
>
Submit another email
</button>
)}
<div className="mt-6 text-center text-[11px] text-zinc-500"> <div className="mt-6 text-center text-[11px] text-zinc-500">
Already invited?{" "} Already invited?{" "}
<a href="/login" className="underline hover:text-zinc-300"> <a href="/login" className="underline hover:text-zinc-300">
@@ -284,6 +344,82 @@ export default function HomePage() {
</div> </div>
</section> </section>
{/* Screenshot Section */}
<section className="relative mt-24">
<div className="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8">
<div className="relative overflow-hidden rounded-2xl border border-white/10 bg-black shadow-2xl">
{/* Screenshot */}
<Image
src="/builder-preview.png"
alt="Battl Builders app screenshot"
width={2400}
height={1400}
priority
className="w-full object-cover"
/>
{/* Bottom fade */}
<div
aria-hidden="true"
className="pointer-events-none absolute inset-x-0 bottom-0 h-24 bg-gradient-to-t from-black"
/>
</div>
</div>
</section>
{/* Info Section */}
<section className="mt-14 rounded-2xl border border-white/10 bg-white/5 px-6 py-14 sm:px-8">
<div className="mx-auto max-w-2xl text-left sm:text-center">
<p className="text-xs font-semibold uppercase tracking-[0.25em] text-amber-300/90">
Everything you need to test the core
</p>
<h2 className="mt-3 text-balance text-3xl font-semibold tracking-tight sm:text-4xl">
Build smarter rifles without the spreadsheet lifestyle.
</h2>
<p className="mt-4 text-sm leading-relaxed text-white/70 sm:text-base">
This private beta is focused on one thing: helping you plan an
AR-15 build faster and with fewer mistakes. Its early, its
evolving, and your feedback will decide what we build next.
</p>
</div>
<dl className="mx-auto mt-10 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-8 text-sm text-white/70 sm:grid-cols-2 lg:max-w-none lg:grid-cols-3">
{features.map((feature) => (
<div
key={feature.name}
className="relative rounded-xl border border-white/10 bg-black/30 p-5"
>
<dt className="flex items-center gap-2 text-sm font-semibold text-white">
<feature.icon
aria-hidden="true"
className="h-5 w-5 text-amber-300"
/>
{feature.name}
</dt>
<dd className="mt-2 text-sm text-white/70">
{feature.description}
</dd>
</div>
))}
</dl>
<div className="mx-auto mt-10 max-w-2xl rounded-xl border border-white/10 bg-black/30 p-5">
<div className="text-xs font-semibold uppercase tracking-[0.25em] text-white/60">
What feedback we want
</div>
<ul className="mt-3 space-y-2 text-sm text-white/80">
<li> Where you got confused or stuck</li>
<li> Warnings that felt wrong (or missing)</li>
<li> Parts you expected to find but couldnt</li>
<li> If this beats your current build-planning process</li>
</ul>
<p className="mt-3 text-xs text-white/50">
By joining the private beta, you agree features, data, and pricing
may change.
</p>
</div>
</section>
{/* Footer strip */} {/* Footer strip */}
<footer className="mt-12 border-t border-zinc-900 pt-4 text-xs text-zinc-500"> <footer className="mt-12 border-t border-zinc-900 pt-4 text-xs text-zinc-500">
<div className="flex flex-wrap items-center justify-between gap-3"> <div className="flex flex-wrap items-center justify-between gap-3">
+19
View File
@@ -8,6 +8,7 @@
"name": "gunbuilder-prototype", "name": "gunbuilder-prototype",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@heroicons/react": "^2.2.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"lucide-react": "^0.555.0", "lucide-react": "^0.555.0",
"next": "14.2.3", "next": "14.2.3",
@@ -139,6 +140,15 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
}, },
"node_modules/@heroicons/react": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz",
"integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==",
"license": "MIT",
"peerDependencies": {
"react": ">= 16 || ^19.0.0-rc"
}
},
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.11.14", "version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -1012,6 +1022,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -1452,6 +1463,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.8.25", "baseline-browser-mapping": "^2.8.25",
"caniuse-lite": "^1.0.30001754", "caniuse-lite": "^1.0.30001754",
@@ -2134,6 +2146,7 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
@@ -2302,6 +2315,7 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@rtsao/scc": "^1.1.0", "@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9", "array-includes": "^3.1.9",
@@ -4531,6 +4545,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.7",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
@@ -4780,6 +4795,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
}, },
@@ -4792,6 +4808,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0", "loose-envify": "^1.1.0",
"scheduler": "^0.23.2" "scheduler": "^0.23.2"
@@ -5796,6 +5813,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -5965,6 +5983,7 @@
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
+1
View File
@@ -9,6 +9,7 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@heroicons/react": "^2.2.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"lucide-react": "^0.555.0", "lucide-react": "^0.555.0",
"next": "14.2.3", "next": "14.2.3",
Binary file not shown.

After

Width:  |  Height:  |  Size: 330 KiB