From 766d97488909b7eee4935ff2b368f573688fdbd8 Mon Sep 17 00:00:00 2001 From: kudindmitriy Date: Sun, 3 May 2026 02:46:14 +0300 Subject: [PATCH] Bob AI: Integrate a small testimonials/social-proof block directly i --- .../sections/hero/HeroBillboardScroll.tsx | 41 ++++++++++++- src/components/ui/AvatarGroup.tsx | 61 ++++++++++++------- src/pages/HomePage.tsx | 13 +++- 3 files changed, 88 insertions(+), 27 deletions(-) diff --git a/src/components/sections/hero/HeroBillboardScroll.tsx b/src/components/sections/hero/HeroBillboardScroll.tsx index 77bed5e..250b633 100644 --- a/src/components/sections/hero/HeroBillboardScroll.tsx +++ b/src/components/sections/hero/HeroBillboardScroll.tsx @@ -1,9 +1,11 @@ import { useRef } from "react"; import { useScroll, useTransform, motion } from "motion/react"; +import { Star } from "lucide-react"; import Button from "@/components/ui/Button"; import HeroBackgroundSlot from "@/components/ui/HeroBackgroundSlot"; import TextAnimation from "@/components/ui/TextAnimation"; import ImageOrVideo from "@/components/ui/ImageOrVideo"; +import AvatarGroup from "@/components/ui/AvatarGroup"; type HeroBillboardScrollProps = { tag: string; @@ -11,6 +13,11 @@ type HeroBillboardScrollProps = { description: string; primaryButton: { text: string; href: string }; secondaryButton: { text: string; href: string }; + socialProof?: { + avatars?: { src: string }[]; + rating?: number; + text: string; + }; } & ({ imageSrc: string; videoSrc?: never } | { videoSrc: string; imageSrc?: never }); const HeroBillboardScroll = ({ @@ -19,6 +26,7 @@ const HeroBillboardScroll = ({ description, primaryButton, secondaryButton, + socialProof, imageSrc, videoSrc, }: HeroBillboardScrollProps) => { @@ -29,11 +37,11 @@ const HeroBillboardScroll = ({ const scale = useTransform(scrollYProgress, [0, 1], [1.05, 1]); return ( -
+
@@ -59,6 +67,33 @@ const HeroBillboardScroll = ({
+ + {socialProof && ( + + {socialProof.avatars && ( + + )} +
+ {socialProof.rating && ( +
+ {Array.from({ length: 5 }).map((_, i) => ( + + ))} +
+ )} + {socialProof.text} +
+
+ )}
@@ -77,4 +112,4 @@ const HeroBillboardScroll = ({ ); }; -export default HeroBillboardScroll; +export default HeroBillboardScroll; \ No newline at end of file diff --git a/src/components/ui/AvatarGroup.tsx b/src/components/ui/AvatarGroup.tsx index 910fbd8..283b327 100644 --- a/src/components/ui/AvatarGroup.tsx +++ b/src/components/ui/AvatarGroup.tsx @@ -9,40 +9,55 @@ interface AvatarGroupProps { className?: string; } -const SIZES = { - sm: "size-8 text-xs", - md: "size-10 text-sm", - lg: "size-12 text-base", -}; +const AvatarGroup = ({ + avatars, + max = 4, + size = "md", + label, + labelClassName = "", + className = "", +}: AvatarGroupProps) => { + const visibleAvatars = avatars.slice(0, max); + const remainingCount = avatars.length - max; -const AvatarGroup = ({ avatars, max = 5, size = "md", label, labelClassName, className = "" }: AvatarGroupProps) => { - const visible = avatars.slice(0, max); - const remaining = avatars.length - visible.length; + const sizeClasses = { + sm: "size-8 text-xs", + md: "size-10 text-sm", + lg: "size-12 text-base", + }; return (
-
- {visible.map((avatar, index) => ( -
+ {visibleAvatars.map((avatar, i) => ( + {`Avatar 0 && "-ml-3" + "rounded-full border-2 border-background object-cover", + sizeClasses[size] + )} + /> + ))} + {remainingCount > 0 && ( +
- -
- ))} - {remaining > 0 && ( -
- +{remaining} + +{remainingCount}
)}
- {label && {label}} + {label && ( + + {label} + + )}
); }; -export default AvatarGroup; +export default AvatarGroup; \ No newline at end of file diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index fbe92b5..62c2f68 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -22,6 +22,17 @@ export default function HomePage() { text: "Visit Us", href: "#contact", }} + socialProof={{ + avatars: [ + { src: "https://images.unsplash.com/photo-1534528741775-53994a69daeb?crop=entropy&cs=tinysrgb&fit=facearea&facepad=2&w=256&h=256&q=80" }, + { src: "https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?crop=entropy&cs=tinysrgb&fit=facearea&facepad=2&w=256&h=256&q=80" }, + { src: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?crop=entropy&cs=tinysrgb&fit=facearea&facepad=2&w=256&h=256&q=80" }, + { src: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?crop=entropy&cs=tinysrgb&fit=facearea&facepad=2&w=256&h=256&q=80" }, + { src: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?crop=entropy&cs=tinysrgb&fit=facearea&facepad=2&w=256&h=256&q=80" } + ], + rating: 5, + text: "Loved by 2,000+ local foodies" + }} imageSrc="https://images.unsplash.com/photo-1579359652478-bdcba0c995ed?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4Mzc5ODl8MHwxfHNlYXJjaHwxMnx8cGFzdHJ5JTIwc2hvcCUyMGF0bW9zcGhlcmUlMjBuYXR1cmFsJTIwbGlnaHRpbmd8ZW58MXwwfHx8MTc3Nzc2NTMzNXww&ixlib=rb-4.1.0&q=80&w=1080" />
@@ -211,4 +222,4 @@ export default function HomePage() { ); -} +} \ No newline at end of file