"use client";
import * as React from "react";
import ElevatorDoorsGallery from "@/components/ui/elevator-doors-gallery";
// An imagined hotel, illustrated with individually sourced stock photography.
export const ELEVATOR_DEMO_ITEMS = [
{
src: "https://cdn.21st.dev/assets/mirror/43/43d4272e70e0353b5b91db831ddbc83b38b4bf4c504dd22fa0e0dd8ba5f1707f.jpg",
alt: "The reception and seating area of a hotel lobby",
floor: 1,
title: "Lobby",
caption: "Check in, breathe out.",
},
{
src: "https://cdn.21st.dev/assets/mirror/0b/0bb94c6d946beae502cc3483376a8c697cd6b8b624be56b2199ea35594f42e40.jpg",
alt: "Exercise equipment in a light-filled fitness center",
floor: 5,
title: "Fitness center",
caption: "Sunrise sessions with a view.",
},
{
src: "https://cdn.21st.dev/assets/mirror/3e/3e3113b502f7dc0cab9eff68b53b0f25d848bfce135ebb94f86f4240d306adcf.jpg",
alt: "A made bed and warm furnishings in a hotel guest suite",
floor: 12,
title: "Guest suite",
caption: "Your room, your pace.",
},
{
src: "https://cdn.21st.dev/assets/mirror/d4/d4bf0449edfb95eea1ea2fc0fd8a6ffa6fbc82b0e17d33ec341908715201dc35.jpg",
alt: "Softly lit seating in a hotel lounge bar",
floor: 20,
title: "Lounge bar",
caption: "Cocktails after dark.",
},
{
src: "https://cdn.21st.dev/assets/mirror/63/63e42ad51c42347f92776506d16610e142cd5f091ba38649065f5947ca00864d.jpg",
alt: "Atmospheric lighting inside a club",
floor: 28,
title: "Club",
caption: "The night goes up.",
},
{
src: "https://cdn.21st.dev/assets/mirror/b9/b96f8f7b648279339e62ec6188611c4838473f8e48acbb4a5468d5d37b16d9a7.jpg",
alt: "A rooftop swimming pool above the city",
floor: 33,
title: "Rooftop pool",
caption: "Swim above the skyline.",
},
];
export default function ElevatorDoorsGalleryDemo({ autoplay = true }: { autoplay?: boolean }) {
const [floor, setFloor] = React.useState(0);
const [inside, setInside] = React.useState(false);
const [replay, setReplay] = React.useState(0);
const [paused, setPaused] = React.useState(false);
const [complete, setComplete] = React.useState(false);
const [reduced, setReduced] = React.useState(false);
React.useEffect(() => {
const media = window.matchMedia("(prefers-reduced-motion: reduce)");
const update = () => setReduced(media.matches);
update();
media.addEventListener("change", update);
return () => media.removeEventListener("change", update);
}, []);
React.useEffect(() => {
if (!autoplay || paused || complete || reduced) return;
const enter = window.setTimeout(() => setInside(true), 4000);
const leave = window.setTimeout(() => { setInside(false); setComplete(true); }, 6200);
return () => { window.clearTimeout(enter); window.clearTimeout(leave); };
}, [autoplay, paused, complete, reduced, replay]);
const restart = () => {
setFloor(0); setInside(false); setPaused(false); setComplete(false);
setReplay((value) => value + 1);
};
return (
<div data-elevator-demo className="flex min-h-svh w-full items-center justify-center bg-background px-5 py-3 text-foreground">
<div className="w-full max-w-[560px]">
<header className="mb-3 flex items-end justify-between gap-4 px-1">
<div>
<p className="mb-1.5 text-[10px] font-medium uppercase tracking-[0.2em] text-muted-foreground">Every floor, a different scene</p>
<h2 className="text-[clamp(21px,3.4vw,27px)] font-medium leading-tight tracking-tight">Hotel elevator gallery</h2>
</div>
<button
data-replay
type="button"
onClick={restart}
className="mb-0.5 flex shrink-0 items-center gap-1.5 rounded-full border border-border px-3 py-2 text-xs text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"
>
<svg aria-hidden="true" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7"><path d="M3 10a9 9 0 1 1 2.6 8.4M3 4v6h6" /></svg>
Replay
</button>
</header>
<ElevatorDoorsGallery
key={replay}
items={ELEVATOR_DEMO_ITEMS}
floor={floor}
onFloorChange={setFloor}
inside={inside}
onInsideChange={setInside}
autoplay={autoplay && !paused && !complete && !reduced}
initialDelay={1400}
interval={20000}
onPointerDownCapture={() => setPaused(true)}
onKeyDownCapture={(event) => {
if (["ArrowUp", "ArrowDown", "Home", "End", "Enter", " ", "Escape"].includes(event.key)) setPaused(true);
}}
/>
<footer className="mt-2 flex items-center justify-between gap-3 px-1 text-[10px] text-muted-foreground">
<p>Six floors. Pick one, then step inside.<span className="ml-2 opacity-60">Demo</span></p>
{autoplay && <button
data-pause
type="button"
aria-pressed={paused || complete}
onClick={() => { if (paused || complete) restart(); else setPaused(true); }}
className="shrink-0 rounded px-1 py-1 outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring motion-reduce:hidden"
>
{complete ? "Replay tour" : paused ? "Resume tour" : "Pause tour"}
</button>}
</footer>
</div>
</div>
);
}