Files
sass-mohfarawati/components/layout/site-logo.tsx
T
2026-03-10 17:14:52 +01:00

112 lines
3.2 KiB
TypeScript

"use client";
import { motion, useAnimationControls, useReducedMotion } from "framer-motion";
import Image from "next/image";
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";
type SiteLogoProps = {
lightLogoUrl?: string | null;
darkLogoUrl?: string | null;
alt: string;
priority?: boolean;
className?: string;
replayKey?: number;
direction?: "rtl" | "ltr";
};
export function SiteLogo({
lightLogoUrl,
darkLogoUrl,
alt,
priority = false,
className,
replayKey = 0,
direction = "ltr",
}: SiteLogoProps) {
const { theme, resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);
const containerControls = useAnimationControls();
const spinControls = useAnimationControls();
const reducedMotion = useReducedMotion();
const directionalOffset = direction === "rtl" ? 42 : -42;
const spinStart = direction === "rtl" ? -360 : 360;
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (reducedMotion) {
return;
}
containerControls.set({
opacity: 0,
x: directionalOffset,
scale: 0.88,
filter: "blur(8px)",
});
spinControls.set({ rotate: 0 });
void containerControls.start({
opacity: 1,
x: 0,
scale: 1,
filter: "blur(0px)",
transition: {
x: { duration: 0.78, ease: [0.22, 1, 0.36, 1] },
opacity: { duration: 0.46 },
scale: { duration: 0.72, ease: [0.22, 1, 0.36, 1] },
filter: { duration: 0.42, ease: [0.22, 1, 0.36, 1] },
},
});
void spinControls.start({
rotate: spinStart,
transition: {
duration: 0.78,
ease: [0.22, 1, 0.36, 1],
},
});
}, [containerControls, directionalOffset, reducedMotion, replayKey, spinControls, spinStart]);
const activeTheme = theme === "system" ? resolvedTheme : theme;
const isDark = mounted && activeTheme === "dark";
const fallbackSrc = isDark ? "/logos/dark-primary.svg" : "/logos/light-primary.svg";
const src = isDark ? darkLogoUrl || lightLogoUrl || fallbackSrc : lightLogoUrl || darkLogoUrl || fallbackSrc;
return (
<motion.span
className="block transform-gpu [transform-style:preserve-3d]"
initial={reducedMotion ? false : undefined}
animate={reducedMotion ? undefined : containerControls}
transition={{ duration: 0.32, ease: [0.22, 1, 0.36, 1] }}
whileHover={reducedMotion ? undefined : { scale: 1.03, y: -1.5, rotate: -1.25 }}
whileTap={reducedMotion ? undefined : { scale: 0.97, rotate: 1.5, y: 0.5 }}
>
<motion.span
className="block origin-center"
initial={reducedMotion ? false : { rotate: 0 }}
animate={reducedMotion ? undefined : spinControls}
>
<Image
src={src}
alt={alt}
width={360}
height={92}
sizes="240px"
className={cn(
"h-10 w-auto object-contain object-left drop-shadow-[0_10px_24px_rgba(15,23,42,0.12)] transition-opacity duration-300 ease-out",
mounted ? "opacity-100" : "opacity-0",
className,
)}
priority={priority}
/>
</motion.span>
</motion.span>
);
}