Files
highland_games_website/app/components/Newsletter.tsx
T
2026-06-22 23:03:02 +02:00

84 lines
2.3 KiB
TypeScript

"use client";
import { useActionState } from "react";
import { useFormStatus } from "react-dom";
import { subscribe, type SubscribeState } from "@/app/actions/subscribe";
const initialState: SubscribeState = { status: "idle", message: "" };
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button
type="submit"
disabled={pending}
className="px-6 py-3 bg-accent text-background font-display tracking-widest text-sm hover:bg-foreground hover:scale-[1.03] transition duration-200 disabled:opacity-60 disabled:cursor-not-allowed disabled:hover:scale-100"
>
{pending ? "SENDING…" : "SUBSCRIBE"}
</button>
);
}
type Props = {
variant?: "default" | "compact";
};
export function Newsletter({ variant = "default" }: Props) {
const [state, formAction] = useActionState(subscribe, initialState);
const wrapperClass =
variant === "compact"
? "w-full max-w-lg"
: "w-full max-w-lg mx-auto";
return (
<form
action={formAction}
className={wrapperClass}
aria-describedby="newsletter-status"
>
{/* honeypot for bots */}
<input
type="text"
name="website"
tabIndex={-1}
autoComplete="off"
className="hidden"
aria-hidden
/>
<label htmlFor="newsletter-email" className="sr-only">
Email address
</label>
<div className="flex flex-col sm:flex-row gap-3">
<input
id="newsletter-email"
type="email"
name="email"
required
placeholder="your@email.com"
className="flex-1 min-w-0 bg-surface border border-border px-4 py-3 text-sm text-foreground placeholder:text-foreground-muted focus:outline-none focus:border-accent transition-colors"
/>
<SubmitButton />
</div>
<p
id="newsletter-status"
role="status"
aria-live="polite"
className={`text-xs tracking-widest mt-3 ${
variant === "compact" ? "" : "text-center"
} ${
state.status === "success"
? "text-accent"
: state.status === "error"
? "text-red-400"
: "text-foreground-muted"
}`}
>
{state.message ||
"No spam. One devblog email per major update. Unsubscribe anytime."}
</p>
</form>
);
}