A newsletter's closing section. The sun sets as it comes into view, and subscribing brings the night and the moon out.
registry/demos/golden-hour-cta-demo.tsx
"use client";
import * as React from "react";
import { useInView } from "motion/react";
import { GoldenHour } from "@/components/ui/golden-hour";
// Golden hour on the way down the page, the sun just set once the section is
// in view, and night with the moon up after the visitor subscribes.
const ARRIVING = 17.6;
const ARRIVED = 19;
const SUBSCRIBED = 21.6;
export function GoldenHourCtaDemo() {
const ref = React.useRef<HTMLDivElement>(null);
const inView = useInView(ref, { amount: 0.6 });
const [email, setEmail] = React.useState("");
const [sent, setSent] = React.useState(false);
const hour = sent ? SUBSCRIBED : inView ? ARRIVED : ARRIVING;
return (
<div ref={ref} className="w-full max-w-4xl">
<GoldenHour
time={hour}
horizon={0.68}
className="flex min-h-[30rem] flex-col items-center rounded-3xl px-6 pt-14 text-center text-white sm:min-h-[32rem] sm:pt-20"
>
<p className="flex items-center gap-2 text-sm font-medium text-white/80">
<SunMark className="size-4" />
Long Light · Fridays
</p>
<h2 className="mt-4 max-w-[17ch] text-4xl/[1.05] font-medium tracking-[-0.035em] text-balance sm:text-5xl/[1.02]">
One slow email a week, sent at sunset.
</h2>
<p className="mt-4 max-w-md text-base/7 text-pretty text-white/80">
Five places worth the detour, and the hour to be there. Read by 18,000 people who would rather be outside.
</p>
<div className="mt-8 w-full max-w-md" aria-live="polite">
{sent ? (
<div className="flex min-h-[52px] items-center justify-center gap-2 rounded-full bg-zinc-950/20 px-5 py-2 text-sm font-medium ring-1 ring-white/25 backdrop-blur-xl">
<CheckIcon className="size-4" />
You're on the list. The first letter lands Friday, just before sunset.
</div>
) : (
<form
onSubmit={(event) => {
event.preventDefault();
if (email.includes("@")) setSent(true);
}}
className="flex h-[52px] items-center gap-2 rounded-full bg-zinc-950/20 p-1.5 ring-1 ring-white/25 backdrop-blur-xl focus-within:ring-white/60"
>
<label htmlFor="golden-hour-cta-email" className="sr-only">
Email
</label>
<input
id="golden-hour-cta-email"
type="email"
required
value={email}
onChange={(event) => setEmail(event.target.value)}
placeholder="you@example.com"
className="h-full min-w-0 flex-1 bg-transparent pl-4 text-sm text-white outline-none placeholder:text-white/70"
/>
<button
type="submit"
className="h-full shrink-0 rounded-full bg-white px-5 text-sm font-medium text-zinc-950 transition-[background-color,scale] duration-150 ease-out hover:bg-white/90 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white active:scale-[0.97]"
>
Subscribe
</button>
</form>
)}
</div>
<p className="mt-3 text-xs text-white/70">No spam. Unsubscribe in one click.</p>
</GoldenHour>
</div>
);
}
function SunMark({ className }: { className?: string }) {
return (
<svg viewBox="0 0 16 16" className={className} fill="none" stroke="currentColor" strokeWidth={1.4} aria-hidden>
<path d="M2 11.5h12M4.5 11.5a3.5 3.5 0 0 1 7 0M8 3v1.6M3.4 5.4l1.1 1.1M12.6 5.4l-1.1 1.1" strokeLinecap="round" />
</svg>
);
}
function CheckIcon({ className }: { className?: string }) {
return (
<svg viewBox="0 0 16 16" className={className} fill="none" stroke="currentColor" strokeWidth={1.8} aria-hidden>
<path d="m3.5 8.5 3 3 6-7" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
}
Live preview, examples and props: https://keyframeui.com/components/golden-hour#golden-hour-cta-demo