|
|
|
|
@@ -6,6 +6,7 @@ import HeroBackgrounds, { type HeroBackgroundVariantProps } from "@/components/b
|
|
|
|
|
import LogoMarquee, { type MarqueeItem } from "@/components/shared/LogoMarquee";
|
|
|
|
|
import { cls } from "@/lib/utils";
|
|
|
|
|
import { useButtonAnimation } from "@/components/hooks/useButtonAnimation";
|
|
|
|
|
import { useState } from "react";
|
|
|
|
|
import type { LucideIcon } from "lucide-react";
|
|
|
|
|
import type { ButtonConfig, ButtonAnimationType } from "@/types/button";
|
|
|
|
|
import type { Avatar } from "@/components/shared/AvatarGroup";
|
|
|
|
|
@@ -70,45 +71,46 @@ interface HeroBillboardProps {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const HeroBillboard = ({
|
|
|
|
|
title,
|
|
|
|
|
description,
|
|
|
|
|
background,
|
|
|
|
|
tag,
|
|
|
|
|
tagIcon,
|
|
|
|
|
tagAnimation,
|
|
|
|
|
buttons,
|
|
|
|
|
buttonAnimation,
|
|
|
|
|
avatars,
|
|
|
|
|
avatarText,
|
|
|
|
|
imageSrc,
|
|
|
|
|
videoSrc,
|
|
|
|
|
imageAlt = "",
|
|
|
|
|
videoAriaLabel = "Hero video",
|
|
|
|
|
mediaAnimation = "none",
|
|
|
|
|
marqueeItems,
|
|
|
|
|
marqueeSpeed = 30,
|
|
|
|
|
showMarqueeCard = true,
|
|
|
|
|
ariaLabel = "Hero section",
|
|
|
|
|
className = "",
|
|
|
|
|
containerClassName = "",
|
|
|
|
|
textBoxClassName = "",
|
|
|
|
|
titleClassName = "",
|
|
|
|
|
descriptionClassName = "",
|
|
|
|
|
tagClassName = "",
|
|
|
|
|
avatarGroupClassName = "",
|
|
|
|
|
buttonContainerClassName = "",
|
|
|
|
|
buttonClassName = "",
|
|
|
|
|
buttonTextClassName = "",
|
|
|
|
|
mediaWrapperClassName = "",
|
|
|
|
|
imageClassName = "",
|
|
|
|
|
marqueeClassName = "",
|
|
|
|
|
marqueeItemClassName = "",
|
|
|
|
|
marqueeCardClassName = "",
|
|
|
|
|
marqueeImageClassName = "",
|
|
|
|
|
marqueeTextClassName = "",
|
|
|
|
|
marqueeIconClassName = "",
|
|
|
|
|
title,
|
|
|
|
|
description,
|
|
|
|
|
background,
|
|
|
|
|
tag,
|
|
|
|
|
tagIcon,
|
|
|
|
|
tagAnimation,
|
|
|
|
|
buttons,
|
|
|
|
|
buttonAnimation,
|
|
|
|
|
avatars,
|
|
|
|
|
avatarText,
|
|
|
|
|
imageSrc,
|
|
|
|
|
videoSrc,
|
|
|
|
|
imageAlt = "",
|
|
|
|
|
videoAriaLabel = "Hero video",
|
|
|
|
|
mediaAnimation = "none",
|
|
|
|
|
marqueeItems,
|
|
|
|
|
marqueeSpeed = 30,
|
|
|
|
|
showMarqueeCard = true,
|
|
|
|
|
ariaLabel = "Hero section",
|
|
|
|
|
className = "",
|
|
|
|
|
containerClassName = "",
|
|
|
|
|
textBoxClassName = "",
|
|
|
|
|
titleClassName = "",
|
|
|
|
|
descriptionClassName = "",
|
|
|
|
|
tagClassName = "",
|
|
|
|
|
avatarGroupClassName = "",
|
|
|
|
|
buttonContainerClassName = "",
|
|
|
|
|
buttonClassName = "",
|
|
|
|
|
buttonTextClassName = "",
|
|
|
|
|
mediaWrapperClassName = "",
|
|
|
|
|
imageClassName = "",
|
|
|
|
|
marqueeClassName = "",
|
|
|
|
|
marqueeItemClassName = "",
|
|
|
|
|
marqueeCardClassName = "",
|
|
|
|
|
marqueeImageClassName = "",
|
|
|
|
|
marqueeTextClassName = "",
|
|
|
|
|
marqueeIconClassName = "",
|
|
|
|
|
}: HeroBillboardProps) => {
|
|
|
|
|
const { containerRef: mediaContainerRef } = useButtonAnimation({ animationType: mediaAnimation });
|
|
|
|
|
const { containerRef: mediaContainerRef } = useButtonAnimation({ animationType: mediaAnimation });
|
|
|
|
|
const [isHovering, setIsHovering] = useState(false);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<section
|
|
|
|
|
@@ -139,30 +141,35 @@ const HeroBillboard = ({
|
|
|
|
|
center={true}
|
|
|
|
|
/>
|
|
|
|
|
<div className="flex flex-col gap-6" >
|
|
|
|
|
<div ref={mediaContainerRef} className={cls("w-full overflow-hidden rounded-theme-capped card p-4 [perspective:1000px]", mediaWrapperClassName)}>
|
|
|
|
|
<style>{`
|
|
|
|
|
@keyframes infiniteSpin {
|
|
|
|
|
from {
|
|
|
|
|
transform: rotate(0deg);
|
|
|
|
|
}
|
|
|
|
|
to {
|
|
|
|
|
transform: rotate(360deg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.spin-infinite {
|
|
|
|
|
animation: infiniteSpin 8s linear infinite;
|
|
|
|
|
}
|
|
|
|
|
`}</style>
|
|
|
|
|
<div className="spin-infinite w-full h-full [transform-style:preserve-3d]">
|
|
|
|
|
<MediaContent
|
|
|
|
|
imageSrc={imageSrc}
|
|
|
|
|
videoSrc={videoSrc}
|
|
|
|
|
imageAlt={imageAlt}
|
|
|
|
|
videoAriaLabel={videoAriaLabel}
|
|
|
|
|
imageClassName={cls("z-1 aspect-square md:aspect-video", imageClassName)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
ref={mediaContainerRef}
|
|
|
|
|
className={cls("w-full overflow-hidden rounded-theme-capped card p-4 [perspective:1000px]", mediaWrapperClassName)}
|
|
|
|
|
onMouseEnter={() => setIsHovering(true)}
|
|
|
|
|
onMouseLeave={() => setIsHovering(false)}
|
|
|
|
|
>
|
|
|
|
|
<style>{`
|
|
|
|
|
@keyframes infiniteSpin {
|
|
|
|
|
from {
|
|
|
|
|
transform: rotate(0deg);
|
|
|
|
|
}
|
|
|
|
|
to {
|
|
|
|
|
transform: rotate(360deg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.spin-on-hover {
|
|
|
|
|
animation: infiniteSpin 8s linear infinite;
|
|
|
|
|
}
|
|
|
|
|
`}</style>
|
|
|
|
|
<div className={cls("w-full h-full [transform-style:preserve-3d]", isHovering && "spin-on-hover")}>
|
|
|
|
|
<MediaContent
|
|
|
|
|
imageSrc={imageSrc}
|
|
|
|
|
videoSrc={videoSrc}
|
|
|
|
|
imageAlt={imageAlt}
|
|
|
|
|
videoAriaLabel={videoAriaLabel}
|
|
|
|
|
imageClassName={cls("z-1 aspect-square md:aspect-video", imageClassName)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
{marqueeItems && marqueeItems.length > 0 && (
|
|
|
|
|
<LogoMarquee
|
|
|
|
|
items={marqueeItems}
|
|
|
|
|
|