Skip to content

Commit 9eb9ab6

Browse files
jarvisclaude
authored andcommitted
feat: add loading states and contact page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent bc9a099 commit 9eb9ab6

2 files changed

Lines changed: 74 additions & 0 deletions

File tree

app/contact/page.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
'use client'
2+
import { useState } from 'react'
3+
4+
export default function ContactPage() {
5+
const [sent, setSent] = useState(false)
6+
const [form, setForm] = useState({ name: '', email: '', message: '' })
7+
8+
const handleSubmit = (e: React.FormEvent) => {
9+
e.preventDefault()
10+
// Store in localStorage as fallback
11+
const contacts = JSON.parse(localStorage.getItem('contact-submissions') || '[]')
12+
contacts.push({ ...form, timestamp: new Date().toISOString() })
13+
localStorage.setItem('contact-submissions', JSON.stringify(contacts))
14+
setSent(true)
15+
}
16+
17+
return (
18+
<div className="min-h-screen bg-zinc-950 flex items-center justify-center px-6">
19+
<div className="w-full max-w-lg">
20+
<a href="/" className="text-sm text-zinc-500 hover:text-white transition-colors mb-8 inline-block">&larr; Back</a>
21+
22+
{sent ? (
23+
<div className="text-center py-16">
24+
<div className="mx-auto w-16 h-16 rounded-full bg-emerald-500/20 flex items-center justify-center mb-6">
25+
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#10b981" strokeWidth="2.5"><polyline points="20 6 9 17 4 12" /></svg>
26+
</div>
27+
<h1 className="text-2xl font-bold text-white mb-3">Message sent!</h1>
28+
<p className="text-zinc-400">We'll get back to you as soon as possible.</p>
29+
</div>
30+
) : (
31+
<>
32+
<h1 className="text-3xl font-bold text-white mb-2">Contact Us</h1>
33+
<p className="text-zinc-400 mb-8">Have a question or feedback? We'd love to hear from you.</p>
34+
35+
<form onSubmit={handleSubmit} className="space-y-5">
36+
<div>
37+
<label className="block text-sm font-medium text-zinc-300 mb-1.5">Name</label>
38+
<input type="text" required value={form.name} onChange={e => setForm({...form, name: e.target.value})}
39+
className="w-full rounded-xl border border-zinc-700 bg-zinc-800 px-4 py-3 text-sm text-white placeholder:text-zinc-600 focus:border-zinc-500 focus:outline-none transition-colors"
40+
placeholder="Your name" />
41+
</div>
42+
<div>
43+
<label className="block text-sm font-medium text-zinc-300 mb-1.5">Email</label>
44+
<input type="email" required value={form.email} onChange={e => setForm({...form, email: e.target.value})}
45+
className="w-full rounded-xl border border-zinc-700 bg-zinc-800 px-4 py-3 text-sm text-white placeholder:text-zinc-600 focus:border-zinc-500 focus:outline-none transition-colors"
46+
placeholder="you@example.com" />
47+
</div>
48+
<div>
49+
<label className="block text-sm font-medium text-zinc-300 mb-1.5">Message</label>
50+
<textarea required rows={5} value={form.message} onChange={e => setForm({...form, message: e.target.value})}
51+
className="w-full rounded-xl border border-zinc-700 bg-zinc-800 px-4 py-3 text-sm text-white placeholder:text-zinc-600 focus:border-zinc-500 focus:outline-none transition-colors resize-none"
52+
placeholder="How can we help?" />
53+
</div>
54+
<button type="submit"
55+
className="w-full rounded-xl bg-white text-black py-3.5 font-semibold hover:bg-zinc-200 transition-colors">
56+
Send Message
57+
</button>
58+
</form>
59+
</>
60+
)}
61+
</div>
62+
</div>
63+
)
64+
}

app/loading.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export default function Loading() {
2+
return (
3+
<div className="min-h-screen bg-zinc-950 flex items-center justify-center">
4+
<div className="flex flex-col items-center gap-4">
5+
<div className="w-8 h-8 border-2 border-zinc-700 border-t-white rounded-full animate-spin" />
6+
<p className="text-sm text-zinc-500">Loading...</p>
7+
</div>
8+
</div>
9+
)
10+
}

0 commit comments

Comments
 (0)