Docs
Hero Section
A hero section with interactivity
requires-interactionhover
Installation
Update tailwind.config.js
theme: {
extend: {
keyframes: {
fadeIn: {
from: { opacity: "0" },
to: { opacity: "1" },
},
},
},
animation: {
fadeIn: "fadeIn 0.5s ease-in",
},
},
Run the following command
It will create a new file called hero-section.tsx
inside the components/animata/hero
directory.
touch components/animata/hero/hero-section.tsx
Paste the code
Open the newly created file and paste the following code:
import { useState } from "react";
import { Button as UIButton } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import animataImage from "@/public/android-chrome-192x192.png";
import TypingText from "../text/typing-text";
import WaveReveal from "../text/wave-reveal";
import Cycling from "../widget/cycling";
import DirectionCard, { testDirectionProps } from "../widget/direction-card";
import WaterTracker from "../widget/water-tracker";
// Button Component
function Button({ children }: { children: React.ReactNode }) {
return (
<UIButton className="w-32 bg-gradient-to-r from-blue-400 to-sky-300">
<p>{children}</p>
</UIButton>
);
}
// ImageWithWave Component
function ImageWithWave() {
return (
<div className="title-logo relative inline-block self-center md:self-start">
<img
width={100}
height={100}
src={animataImage.src}
className="-top-6 h-10 w-10 translate-y-5 animate-fadeIn fade-in-0 md:-top-10 md:h-16 md:w-16 md:translate-y-0"
alt="Hero image"
/>
<WaveReveal
className="my-4 pl-[0px] text-slate-300 sm:text-[60px] md:px-0 md:text-[70px] lg:text-[80px]"
text="ANIMATA"
/>
</div>
);
}
// CardLabel Component
function CardLabel({ text }: { text: string }) {
return (
<div className="mb-3 mt-2 flex w-full justify-center rounded-xl bg-slate-800 p-2">
<TypingText repeat={false} className="w-full self-start text-yellow-300" text={text} />
</div>
);
}
// Card Component
function Card({ card, index, stackAlign }: { card: string; index: number; stackAlign: boolean }) {
const cardContent = () => {
switch (card) {
case "card1":
return (
<>
<Cycling />
<CardLabel text="Cycling Card" />
</>
);
case "card2":
return (
<>
<DirectionCard {...testDirectionProps} />
<CardLabel text="Direction Card" />
</>
);
case "card3":
return (
<>
<WaterTracker dailyGoal={3000} />
<CardLabel text="Water Tracker" />
</>
);
default:
return null;
}
};
return (
<div
style={{ boxShadow: index !== 2 ? "inset 0px -10px 30px 0px #1e293b" : "none" }}
key={index}
className={cn(
`absolute inset-0 text-center text-gray-800 z-${index} ${card} my-6 flex h-full w-full flex-col items-center justify-around rounded-2xl transition-all duration-700 ease-out`,
card === "card1" && stackAlign && "ml-8 md:ml-0",
card === "card2" && (!stackAlign ? "-rotate-[15deg]" : "-left-8 ml-8 rotate-0 md:ml-0"),
card === "card3" && (!stackAlign ? "rotate-[15deg]" : "-left-16 ml-8 rotate-0 md:ml-0"),
index === 0 && "scale-90 bg-slate-900",
index === 1 && "scale-95 bg-slate-700",
index === 2 && `scale-100 bg-slate-500 ${stackAlign && "bg-slate-600"}`,
)}
>
<div className="component-container mt-6 flex h-full flex-col justify-around">
{cardContent()}
</div>
</div>
);
}
// InfoContainer Component
function InfoContainer({ changeStackAlign }: { changeStackAlign: (card: string) => void }) {
const underlinedWord = (text: string, card: string) => (
<span
onMouseOver={() => changeStackAlign(card)}
className="cursor-pointer underline decoration-yellow-300 decoration-wavy"
>
{" "}
{text}
</span>
);
return (
<div className="info-container flex flex-col items-center md:w-[60%] md:items-start">
<ImageWithWave />
<p className="w-full animate-fadeIn text-center text-lg leading-8 text-gray-300 md:w-[80%] md:text-left">
Hand-crafted ✍️ interaction animations and effects from around the internet, designed to be{" "}
{underlinedWord("Beautiful", "card1")}, {underlinedWord("Functional", "card2")}, and{" "}
{underlinedWord("Interactive", "card3")} 🌍. Ready to copy and paste into your project to
enhance its aesthetic and usability.
</p>
<div className="mt-6 flex animate-fadeIn justify-center gap-2 md:justify-start">
<Button>Documentation</Button>
<Button>Contribute</Button>
</div>
</div>
);
}
// HeroSection Component
function HeroSection({ className }: { className?: string }) {
const [stackAlign, setStackAlign] = useState(false);
const [cardStack, setCardStack] = useState(["card3", "card2", "card1"]);
const cardStacks: { [key: string]: string[] } = {
card1: ["card3", "card2", "card1"],
card2: ["card3", "card1", "card2"],
card3: ["card1", "card2", "card3"],
};
const changeStackAlign = (card: string) => {
setStackAlign(true);
const newStack = cardStacks[card];
if (newStack) {
setCardStack(newStack);
}
};
return (
<div className={cn("hero-container dark:bg-slate-800", className)}>
<div className="inner-container m-auto flex h-full w-[90%] flex-col items-center justify-around dark:bg-slate-800 md:flex-row">
<InfoContainer changeStackAlign={changeStackAlign} />
<div className="card-stack-container flex animate-fadeIn items-center justify-center md:m-0 md:w-[40%]">
<div className="cards relative flex h-[350px] w-[280px] items-center justify-between md:h-[350px] md:w-[300px]">
{cardStack.map((card, index) => (
<Card key={index} card={card} index={index} stackAlign={stackAlign} />
))}
</div>
</div>
</div>
</div>
);
}
export default HeroSection;
Credits
Built by Aadarsh Baral