Files
LetsBeBiz-Site/src/components/sections/TrustBar.tsx
Matt 4aa357a999 polish: nav scroll threshold, footer cleanup, hero gradient
- Nav: trigger solid background at 10px scroll (was 100px) to prevent logo/text overlap
- Footer: copyright uses legal name "LetsBe Solutions LLC"
- Footer: location changed to "American-founded. Serving the Côte d'Azur and beyond."
- Footer: remove GitHub social link (no public GitHub)
- Hero: smooth gradient fade into trust bar section (no hard color gap)
- Services: "SEO & Digital Marketing" replaces "SEO & Performance"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:40:15 +01:00

146 lines
3.8 KiB
TypeScript

'use client';
import { motion } from 'framer-motion';
import { useTranslations } from 'next-intl';
import { Compass, Shield, Brain, MapPin } from 'lucide-react';
import { cn } from '@/lib/utils';
import {
revealVariants,
staggerContainerWide,
viewportOnce,
} from '@/lib/animations';
import type { LucideIcon } from 'lucide-react';
// Each item's icon scale-bounce on enter
const iconBounceVariants = {
hidden: { scale: 0.7, opacity: 0 },
visible: {
scale: 1,
opacity: 1,
transition: {
duration: 0.5,
ease: [0.34, 1.56, 0.64, 1] as [number, number, number, number], // spring-like overshoot
},
},
};
interface TrustItem {
key: string;
Icon: LucideIcon;
}
const ITEMS: TrustItem[] = [
{ key: 'customBuilt', Icon: Compass },
{ key: 'privateInfra', Icon: Shield },
{ key: 'aiPowered', Icon: Brain },
{ key: 'rivieraBased', Icon: MapPin },
];
interface TrustCardProps {
item: TrustItem;
index: number;
t: (key: string) => string;
}
function TrustCard({ item, index, t }: TrustCardProps) {
const { Icon, key } = item;
return (
<motion.div
variants={revealVariants}
className={cn(
'group relative flex flex-col items-center text-center gap-4 p-8',
'rounded-2xl bg-surface-high shadow-subtle',
'transition-shadow duration-300 hover:shadow-card',
'overflow-hidden cursor-default',
)}
>
{/* Top accent gradient bar — fades in on hover */}
<span
className={cn(
'pointer-events-none absolute top-0 left-6 right-6 h-[3px] rounded-full',
'opacity-0 group-hover:opacity-100 transition-opacity duration-300',
)}
style={{
background: 'linear-gradient(to right, #006494, #5BA4D9)',
}}
aria-hidden="true"
/>
{/* Icon with scale-bounce on scroll reveal */}
<motion.div
variants={iconBounceVariants}
className={cn(
'flex items-center justify-center w-12 h-12 rounded-full',
'bg-primary/8',
'transition-transform duration-300 ease-out',
'group-hover:-translate-y-1',
)}
aria-hidden="true"
>
<Icon
size={24}
className="text-primary transition-colors duration-300"
strokeWidth={1.75}
/>
</motion.div>
{/* Title */}
<div>
<h3
className={cn(
'font-semibold text-on-surface text-base leading-snug mb-1',
'transition-colors duration-300 group-hover:text-primary-dark',
)}
>
{t(`${key}.title`)}
</h3>
{/* Description */}
<p className="text-sm text-outline leading-relaxed">
{t(`${key}.description`)}
</p>
</div>
</motion.div>
);
}
export default function TrustBar() {
const t = useTranslations('trustBar');
return (
<section
aria-label="Trust indicators"
className="relative bg-surface-low py-12"
>
{/* Gradient bridge — blends hero into this section */}
<div
className="absolute top-0 left-0 right-0 h-24 pointer-events-none"
style={{
background: 'linear-gradient(to bottom, #f8f9fa, transparent)',
}}
aria-hidden="true"
/>
<div className="max-w-6xl mx-auto px-6">
{/* Stagger wrapper — triggers children revealVariants on scroll */}
<motion.div
variants={staggerContainerWide}
initial="hidden"
whileInView="visible"
viewport={viewportOnce}
className="grid grid-cols-2 md:grid-cols-4 gap-6 md:gap-8"
>
{ITEMS.map((item, index) => (
<TrustCard
key={item.key}
item={item}
index={index}
t={t}
/>
))}
</motion.div>
</div>
</section>
);
}