Najjar\NajjarV02 92cf4aba3b
Some checks are pending
CI/CD / test-and-build (push) Waiting to run
CI/CD / deploy (push) Blocked by required conditions
feat: add robotics components and data structures
- Introduced RobotProductCard component for displaying robot details.
- Added WhyUs component highlighting key reasons for choosing our robotics solutions.
- Implemented CursorSpotlight for enhanced user interaction.
- Created GlassPanel for a stylish UI element.
- Developed MotionSection for animated section visibility.
- Added PremiumButton for versatile button options.
- Established data structures for industries and robots, including detailed specifications and use cases.
- Included utility functions for retrieving robots by slug and category.
2026-05-20 17:22:47 +04:00

133 lines
4.4 KiB
TypeScript

"use client";
/**
* Premium horizontal logo marquee.
*
* Setup:
* 1. globals.css must have:
* @keyframes marquee {
* 0% { transform: translateX(0); }
* 100% { transform: translateX(-50%); }
* }
* 2. Pass clients prop or create lib/clients.ts:
* export const clients = [
* { src: "/images/clients/brand-a.png", alt: "Brand A" },
* ...
* ];
*/
import Image from "next/image";
import { useReducedMotion } from "framer-motion";
export type Client = { src: string; alt: string };
export function ClientLogoMarquee({
clients,
eyebrow = "Our Clients",
title,
subtitle,
}: {
clients: Client[];
eyebrow?: string;
title: React.ReactNode;
subtitle?: React.ReactNode;
}) {
const reduce = useReducedMotion();
const loop = [...clients, ...clients];
return (
<section className="relative overflow-hidden py-16 md:py-20 lg:py-24">
<div
aria-hidden
className="pointer-events-none absolute -left-32 top-1/3 size-[480px] rounded-full radial-gold blur-3xl opacity-30"
/>
<div className="mx-auto max-w-7xl px-6 md:px-10">
<div className="flex flex-col items-center gap-6 text-center">
<div className="flex items-center gap-3 text-[11px] font-medium uppercase tracking-[0.22em] text-mist">
<span className="h-px w-8 bg-gold/40" />
<span>{eyebrow}</span>
</div>
<h2 className="font-display text-4xl leading-[1.04] text-bone text-balance md:text-5xl">
{title}
</h2>
{subtitle ? (
<p className="max-w-2xl text-pretty text-mist md:text-lg">{subtitle}</p>
) : null}
</div>
<div className="relative mt-12 md:mt-14">
{/* edge fades */}
<div
aria-hidden
className="pointer-events-none absolute inset-y-0 left-0 z-10 w-16 bg-gradient-to-r from-obsidian to-transparent md:w-32"
/>
<div
aria-hidden
className="pointer-events-none absolute inset-y-0 right-0 z-10 w-16 bg-gradient-to-l from-obsidian to-transparent md:w-32"
/>
<div
className="flex overflow-hidden"
style={{
maskImage:
"linear-gradient(90deg, transparent, black 8%, black 92%, transparent)",
}}
>
{reduce ? (
<ClientGrid clients={clients} />
) : (
<div
className="flex shrink-0 gap-4 pr-4 md:gap-6 md:pr-6"
style={{
animation: "marquee 50s linear infinite",
animationPlayState: "running",
}}
onMouseEnter={(e) =>
(e.currentTarget.style.animationPlayState = "paused")
}
onMouseLeave={(e) =>
(e.currentTarget.style.animationPlayState = "running")
}
>
{loop.map((c, i) => (
<LogoTile key={`${c.src}-${i}`} client={c} />
))}
</div>
)}
</div>
</div>
</div>
</section>
);
}
function LogoTile({ client }: { client: Client }) {
return (
<div className="group/tile relative grid h-24 w-44 shrink-0 place-items-center overflow-hidden rounded-2xl border border-bone/10 bg-graphite/40 px-5 backdrop-blur-sm transition-all duration-500 hover:border-gold/30 hover:bg-graphite/60 md:h-28 md:w-52">
<div
aria-hidden
className="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-700 group-hover/tile:opacity-100"
style={{
background:
"radial-gradient(60% 80% at 50% 50%, rgba(212,164,55,0.18), transparent 70%)",
}}
/>
<Image
src={client.src}
alt={client.alt}
width={200}
height={100}
className="relative max-h-14 w-auto object-contain opacity-70 brightness-[1.05] contrast-[0.9] grayscale transition-all duration-500 group-hover/tile:scale-105 group-hover/tile:opacity-100 group-hover/tile:grayscale-0 md:max-h-16"
/>
</div>
);
}
function ClientGrid({ clients }: { clients: Client[] }) {
return (
<div className="grid w-full grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-6">
{clients.map((c) => (
<LogoTile key={c.src} client={c} />
))}
</div>
);
}