feat: Feature 3.1 — Landing page + blog + Phase 3 specs

Next.js 14+ web app in web/ directory:
- Landing page: Hero, How It Works, Features, 3-tier Pricing with
  founder badges, Footer with email capture
- Blog system: MDX-powered, /blog index + /blog/[slug] pages,
  reading time, Open Graph tags, JSON-LD structured data
- Auth pages: /login + /signup (Supabase Auth ready)
- Design system: dark theme, grade colors (A/B/C/D), BetonBLK voice
- 1 seed blog post: "How to Read Line Movement Like a Sharp"
- Specs for 3.2 (Scan UI), 3.3 (Bet Tracker), 3.4 (Stripe)

Build passes clean: 7 static pages generated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kev
2026-03-22 09:43:38 -04:00
parent ed6502a880
commit bfa8345ebf
26 changed files with 5142 additions and 31 deletions
+63
View File
@@ -0,0 +1,63 @@
'use client';
import { useState } from 'react';
export default function SignupPage() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const handleSignup = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError('');
// TODO: Integrate with Supabase Auth
// const { error } = await supabase.auth.signUp({ email, password });
setLoading(false);
setError('Auth integration pending. Backend is ready.');
};
return (
<section className="min-h-[80vh] flex items-center justify-center px-4">
<div className="w-full max-w-sm">
<h1 className="text-3xl font-bold text-center mb-2">Create Account</h1>
<p className="text-center text-[var(--text-muted)] text-sm mb-8">5 free scans. No credit card required.</p>
<form onSubmit={handleSignup} className="space-y-4">
<div>
<label className="block text-sm text-[var(--text-muted)] mb-1">Email</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="w-full px-4 py-3 rounded-xl bg-[var(--card)] border border-[var(--border)] text-white placeholder:text-[var(--text-muted)] focus:outline-none focus:border-[var(--accent)]"
/>
</div>
<div>
<label className="block text-sm text-[var(--text-muted)] mb-1">Password</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
minLength={8}
className="w-full px-4 py-3 rounded-xl bg-[var(--card)] border border-[var(--border)] text-white placeholder:text-[var(--text-muted)] focus:outline-none focus:border-[var(--accent)]"
/>
</div>
{error && <p className="text-[var(--grade-d)] text-sm">{error}</p>}
<button
type="submit"
disabled={loading}
className="w-full py-3 bg-[var(--accent)] text-white rounded-xl font-medium hover:opacity-90 transition disabled:opacity-50"
>
{loading ? 'Creating account...' : 'Sign Up — Free'}
</button>
</form>
<p className="text-center text-sm text-[var(--text-muted)] mt-6">
Already have an account? <a href="/login" className="text-[var(--accent)] hover:underline">Log in</a>
</p>
</div>
</section>
);
}