feat: add animated components for enhanced UI/UX
- Introduced DrawLine component for drawing animations. - Added LazyRevealImage component for lazy loading images with reveal animations. - Implemented TextDiffuseReveal for animated text reveals with staggered effects. - Created TopProgressBar for a dynamic loading indicator. - Added PointCloud mock for testing animations. - Developed useReducedMotion hook to handle user preferences for reduced motion. - Centralized animation configurations in config.ts for easier management. - Defined animation variants in variants.ts for consistent animation effects. - Established AnimationProvider to supply global animation settings. - Created tests for AnimationProvider and useReducedMotion hook. - Added SVG assets for branding and UI elements. - Documented frontend review plan and hero circuit board animation plan.
This commit is contained in:
1 parent
0ab6930f92
commit
08dd046887
76 files changed
+21682
-1197
No files matched your search
@@ -0,0 +1,114 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* CompanyLogos Component
|
||||
*
|
||||
* Displays an infinite-scrolling banner of company logos after the header.
|
||||
* Features smooth horizontal animation with reduced motion support.
|
||||
*
|
||||
* Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8
|
||||
*/
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import Image from "next/image";
|
||||
import { useReducedMotion } from "@/app/hooks/useReducedMotion";
|
||||
|
||||
// TypeScript interface for company logos
|
||||
export interface CompanyLogo {
|
||||
name: string; // Company name
|
||||
imagePath: string; // Path to logo image (SVG preferred)
|
||||
alt: string; // Alt text for accessibility
|
||||
}
|
||||
|
||||
// Company logos data
|
||||
const companies: CompanyLogo[] = [
|
||||
{
|
||||
name: "Apolo Energia",
|
||||
imagePath: "/logos/apolo.svg",
|
||||
alt: "Apolo Energia logo",
|
||||
},
|
||||
{
|
||||
name: "Julia Beauty Lashes",
|
||||
imagePath: "/logos/julia.svg",
|
||||
alt: "Julia Beauty Lashes logo",
|
||||
},
|
||||
{
|
||||
name: "Innovo",
|
||||
imagePath: "/logos/innovo.svg",
|
||||
alt: "Innovo logo",
|
||||
},
|
||||
{
|
||||
name: "TeraByteShop",
|
||||
imagePath: "/logos/terabyte.svg",
|
||||
alt: "TeraByteShop logo",
|
||||
},
|
||||
{
|
||||
name: "Pichau",
|
||||
imagePath: "/logos/pichau.svg",
|
||||
alt: "Pichau logo",
|
||||
},
|
||||
];
|
||||
|
||||
export default function CompanyLogos() {
|
||||
const shouldReduceMotion = useReducedMotion();
|
||||
|
||||
// Duplicate logo array for seamless infinite scroll
|
||||
const duplicatedLogos = [...companies, ...companies];
|
||||
|
||||
// Static grid for reduced motion preference
|
||||
if (shouldReduceMotion) {
|
||||
return (
|
||||
<section className="w-full border-b border-[rgba(255,255,255,0.06)] bg-[var(--paper)] overflow-hidden">
|
||||
<div className="container mx-auto px-sp-6 py-sp-8 md:px-sp-10 lg:px-sp-16">
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-sp-6 items-center justify-items-center">
|
||||
{companies.map((logo) => (
|
||||
<div key={logo.name} className="flex items-center justify-center">
|
||||
<Image
|
||||
src={logo.imagePath}
|
||||
alt={logo.alt}
|
||||
width={150}
|
||||
height={48}
|
||||
className="h-12 w-auto object-contain grayscale opacity-60"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
// Animated infinite scroll
|
||||
return (
|
||||
<section className="w-full border-b border-[rgba(255,255,255,0.06)] bg-[var(--paper)] overflow-hidden">
|
||||
<div className="py-sp-8">
|
||||
<motion.div
|
||||
className="flex gap-sp-12 items-center"
|
||||
animate={{
|
||||
x: [0, "-50%"],
|
||||
}}
|
||||
transition={{
|
||||
duration: 30,
|
||||
repeat: Infinity,
|
||||
ease: "linear",
|
||||
}}
|
||||
>
|
||||
{duplicatedLogos.map((logo, index) => (
|
||||
<div
|
||||
key={`${logo.name}-${index}`}
|
||||
className="flex-shrink-0 flex items-center justify-center"
|
||||
>
|
||||
<Image
|
||||
src={logo.imagePath}
|
||||
alt={logo.alt}
|
||||
width={150}
|
||||
height={48}
|
||||
className="h-12 w-auto object-contain grayscale hover:grayscale-0 opacity-60 hover:opacity-100 transition-all duration-300"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user