STYLED - Add CSS hero entrance, title halo, and scroll cue
Replace the framer-motion hero entrance with pure-CSS staggered animations so the hero is painted immediately instead of flashing blank until hydration. Add a focused brand glow behind the hero title and an animated scroll cue at the bottom of the home hero. Entrance and cue respect prefers-reduced-motion.
This commit is contained in:
@@ -1,30 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { ArrowDown } from "lucide-react";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { Container } from "@/components/layout/container";
|
||||
import { HeroMotionBackdrop } from "@/components/layout/hero-motion-backdrop";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const heroItemVariants = {
|
||||
hidden: { opacity: 0, y: 16 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.54, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] },
|
||||
},
|
||||
};
|
||||
|
||||
const heroContainerVariants = {
|
||||
hidden: {},
|
||||
visible: {
|
||||
transition: { staggerChildren: 0.13, delayChildren: 0.08 },
|
||||
},
|
||||
};
|
||||
|
||||
type HeroTone = "default" | "accent" | "soft";
|
||||
type HeroLineAlign = "start" | "center" | "end";
|
||||
|
||||
@@ -128,6 +109,14 @@ export function HeroShell({
|
||||
{children}
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
{variant === "home" ? (
|
||||
<HeroScrollLink
|
||||
href="#home-content"
|
||||
label="Scroll to content"
|
||||
className="hero-scroll-anchor hidden sm:inline-flex"
|
||||
/>
|
||||
) : null}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -136,27 +125,14 @@ export function HeroContentMotion({
|
||||
children,
|
||||
className,
|
||||
}: HeroContentMotionProps) {
|
||||
return (
|
||||
<motion.div
|
||||
className={className}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={heroContainerVariants}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
return <div className={cn("hero-content", className)}>{children}</div>;
|
||||
}
|
||||
|
||||
export function HeroMotionItem({
|
||||
children,
|
||||
className,
|
||||
}: HeroContentMotionProps) {
|
||||
return (
|
||||
<motion.div className={className} variants={heroItemVariants}>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
return <div className={cn("hero-rise", className)}>{children}</div>;
|
||||
}
|
||||
|
||||
export function HeroTitle({
|
||||
@@ -167,7 +143,7 @@ export function HeroTitle({
|
||||
}: HeroTitleProps) {
|
||||
const isArabic = locale === "ar";
|
||||
const titleClassName = cn(
|
||||
"text-balance font-semibold text-[hsl(var(--hero-ink))]",
|
||||
"hero-title hero-rise text-balance font-semibold text-[hsl(var(--hero-ink))]",
|
||||
variant === "home"
|
||||
? isArabic
|
||||
? "mt-6 flex w-full max-w-[26rem] flex-col gap-y-1 px-4 text-[clamp(2.85rem,11vw,5.9rem)] leading-[1.06] tracking-[-0.03em] sm:max-w-[30rem] sm:px-0 md:max-w-[36rem] lg:max-w-[32rem]"
|
||||
@@ -177,7 +153,7 @@ export function HeroTitle({
|
||||
);
|
||||
|
||||
return (
|
||||
<motion.h1 className={titleClassName} variants={heroItemVariants}>
|
||||
<h1 className={titleClassName}>
|
||||
{lines.map((line, index) => (
|
||||
<span
|
||||
key={`${index}-${line.text}`}
|
||||
@@ -202,7 +178,7 @@ export function HeroTitle({
|
||||
)}
|
||||
</span>
|
||||
))}
|
||||
</motion.h1>
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user