A continuous 3D mouse-and-touch draggable cover flow showcase with full interactive controls. Includes complete typographic customizers for font color, font size, font style/family, bold, italic, underline, line spacing, and letter spacing, alongside light/dark mode and transparent background toggles. Dragging gestures and cursor states (grab and grabbing) are isolated strictly to the cards.
By Gwyneth Sarigumba
Loading preview...
Install component
"use client";
import React, { useState, useEffect } from "react";
import { cn } from "@/lib/utils";
import CoverFlow from "@/components/ui/3d-sonic-cover-flow-carousel";
// Module-level settings for 21st.dev live panel controls
const settings = {
// Theme & Background Controls
dark: true,
removeBackground: false,
// Typography Controls
fontColor: "",
fontSize: 26,
fontFamily: "system-ui, -apple-system, sans-serif",
bold: true,
italic: false,
underline: false,
lineHeight: 1.15,
letterSpacing: -0.02,
// 3D Carousel Parameters
spacing: 150,
rotationAngle: 45,
perspective: 1000,
scaleStep: 0.08,
showMetadata: true,
autoplay: false,
autoplayInterval: 4500,
};
export default {
DemoOne: function DemoOne(props: Partial<typeof settings>) {
const s = { ...settings, ...props };
const [isVisible, setIsVisible] = useState(false);
const [systemDark, setSystemDark] = useState(true);
useEffect(() => {
const checkTheme = () => {
if (typeof document === "undefined") return;
const isDarkTheme =
document.documentElement.classList.contains("dark") ||
document.body.classList.contains("dark");
setSystemDark(isDarkTheme);
};
checkTheme();
const observer = new MutationObserver(checkTheme);
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
observer.observe(document.body, { attributes: true, attributeFilter: ["class"] });
return () => observer.disconnect();
}, []);
useEffect(() => {
const timer = setTimeout(() => setIsVisible(true), 80);
return () => clearTimeout(timer);
}, []);
const effectiveDark = props.dark !== undefined ? props.dark : (s.dark ?? systemDark);
const staggerClass = cn(
"transition-all duration-700 ease-[cubic-bezier(0.16,1,0.3,1)]",
isVisible ? "opacity-100 translate-y-0 scale-100" : "opacity-0 translate-y-6 scale-95"
);
return (
<div
className={cn(
"relative w-full min-h-screen flex flex-col items-center justify-center p-4 sm:p-8 font-sans transition-colors duration-500",
effectiveDark ? "dark bg-black text-white" : "bg-stone-100 text-zinc-950",
s.removeBackground && "!bg-transparent"
)}
>
<div className={cn("w-full max-w-6xl flex flex-col items-center", staggerClass)}>
<CoverFlow
isDark={effectiveDark}
fontColor={s.fontColor}
fontSize={s.fontSize}
fontFamily={s.fontFamily}
isBold={s.bold}
isItalic={s.italic}
isUnderline={s.underline}
lineHeight={s.lineHeight}
letterSpacing={s.letterSpacing}
spacing={s.spacing}
rotationAngle={s.rotationAngle}
perspective={s.perspective}
scaleStep={s.scaleStep}
showMetadata={s.showMetadata}
autoplay={s.autoplay}
autoplayInterval={s.autoplayInterval}
/>
</div>
</div>
);
},
};