104 lines
5.9 KiB
TypeScript
104 lines
5.9 KiB
TypeScript
'use client';
|
|
import { useState } from 'react';
|
|
import { SITE, GITEA_URL, GITEA_USERNAME } from '@/lib/config';
|
|
|
|
export default function Contact() {
|
|
const [status, setStatus] = useState<'idle'|'sent'>('idle');
|
|
|
|
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
|
e.preventDefault();
|
|
const fd = new FormData(e.currentTarget);
|
|
const name = fd.get('name') as string;
|
|
const email = fd.get('email') as string;
|
|
const message = fd.get('message') as string;
|
|
if (!name || !email || !message) return;
|
|
const sub = encodeURIComponent(`Message from ${name} via williammarch.xyz`);
|
|
const body = encodeURIComponent(`From: ${name} <${email}>\n\n${message}`);
|
|
window.location.href = `mailto:${SITE.email}?subject=${sub}&body=${body}`;
|
|
setStatus('sent');
|
|
}
|
|
|
|
return (
|
|
<section id="contact" className="py-24 px-6 bg-[#0a0a0a]" aria-labelledby="contact-heading">
|
|
<div className="max-w-5xl mx-auto">
|
|
<span className="label">Get in touch</span>
|
|
<h2 id="contact-heading"
|
|
className="text-[clamp(1.8rem,4vw,2.5rem)] font-black tracking-tight text-white mb-10">
|
|
Let’s work together.
|
|
</h2>
|
|
|
|
<div className="grid md:grid-cols-[280px_1fr] gap-6">
|
|
{/* Links */}
|
|
<div className="flex flex-col gap-3">
|
|
<a href={`mailto:${SITE.email}`}
|
|
className="glass rounded-xl p-4 flex items-center gap-3 group hover:border-white/[0.14]
|
|
hover:-translate-x-[-4px] transition-all duration-150">
|
|
<div className="w-8 h-8 rounded-lg bg-white/[0.05] flex items-center justify-center flex-shrink-0" aria-hidden="true">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.5)" strokeWidth="1.8">
|
|
<rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/>
|
|
</svg>
|
|
</div>
|
|
<div className="min-w-0">
|
|
<p className="text-[10px] text-white/25 uppercase tracking-wider">Email</p>
|
|
<p className="text-xs font-medium text-white/55 truncate group-hover:text-white/80 transition-colors">{SITE.email}</p>
|
|
</div>
|
|
</a>
|
|
<a href={`${GITEA_URL}/${GITEA_USERNAME}`}
|
|
target="_blank" rel="noopener noreferrer"
|
|
className="glass rounded-xl p-4 flex items-center gap-3 group hover:border-white/[0.14]
|
|
hover:translate-x-1 transition-all duration-150">
|
|
<div className="w-8 h-8 rounded-lg bg-white/[0.05] flex items-center justify-center flex-shrink-0" aria-hidden="true">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.5)" strokeWidth="1.8">
|
|
<path d="M15 22v-4a4.8 4.8 0 0 0-1-3.2c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/>
|
|
<path d="M9 18c-4.51 2-5-2-7-2"/>
|
|
</svg>
|
|
</div>
|
|
<div className="min-w-0">
|
|
<p className="text-[10px] text-white/25 uppercase tracking-wider">Gitea</p>
|
|
<p className="text-xs font-medium text-white/55 truncate group-hover:text-white/80 transition-colors font-mono">
|
|
{GITEA_URL.replace(/^https?:\/\//, '')}/{GITEA_USERNAME}
|
|
</p>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
{/* Form */}
|
|
<form onSubmit={handleSubmit} className="glass rounded-xl p-6 flex flex-col gap-4" noValidate>
|
|
<div className="grid sm:grid-cols-2 gap-4">
|
|
<label className="flex flex-col gap-1.5">
|
|
<span className="text-[10px] font-semibold uppercase tracking-wider text-white/30">Name</span>
|
|
<input name="name" type="text" required placeholder="Your name" autoComplete="name"
|
|
className="bg-white/[0.03] border border-white/[0.08] rounded-lg px-3 py-2.5 text-sm
|
|
text-white placeholder-white/20 outline-none transition-colors
|
|
focus:border-white/[0.2] focus:ring-1 focus:ring-white/[0.1]" />
|
|
</label>
|
|
<label className="flex flex-col gap-1.5">
|
|
<span className="text-[10px] font-semibold uppercase tracking-wider text-white/30">Email</span>
|
|
<input name="email" type="email" required placeholder="you@example.com" autoComplete="email"
|
|
className="bg-white/[0.03] border border-white/[0.08] rounded-lg px-3 py-2.5 text-sm
|
|
text-white placeholder-white/20 outline-none transition-colors
|
|
focus:border-white/[0.2] focus:ring-1 focus:ring-white/[0.1]" />
|
|
</label>
|
|
</div>
|
|
<label className="flex flex-col gap-1.5">
|
|
<span className="text-[10px] font-semibold uppercase tracking-wider text-white/30">Message</span>
|
|
<textarea name="message" required placeholder="What's on your mind?" rows={4}
|
|
className="bg-white/[0.03] border border-white/[0.08] rounded-lg px-3 py-2.5 text-sm
|
|
text-white placeholder-white/20 outline-none resize-none transition-colors
|
|
focus:border-white/[0.2] focus:ring-1 focus:ring-white/[0.1]" />
|
|
</label>
|
|
<div className="flex items-center gap-4">
|
|
<button type="submit" className="btn btn-primary">
|
|
{status === 'sent' ? 'Opening email…' : 'Send message'}
|
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" aria-hidden="true">
|
|
<line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|