106 lines
3.6 KiB
TypeScript
106 lines
3.6 KiB
TypeScript
"use client";
|
|
import { useState, useEffect } from "react";
|
|
import { motion } from "framer-motion";
|
|
import Loader from "../components/Loader";
|
|
import { useTechPartners } from "../services/techPartners";
|
|
import { assetUrl } from "../services/api";
|
|
import type { ThemeProps } from "../types";
|
|
|
|
function PartnersInner({ isNavyBg }: ThemeProps) {
|
|
const { data, isLoading } = useTechPartners();
|
|
|
|
const bg = isNavyBg ? "#071233" : "#f7f6f3";
|
|
const border = isNavyBg ? "rgba(255,255,255,0.07)" : "rgba(0,0,0,0.07)";
|
|
const label = isNavyBg ? "rgba(255,255,255,0.28)" : "rgba(0,0,0,0.28)";
|
|
|
|
const partners = (data ?? []).filter((p) => p.isActive && p.logoUrl).sort((a, b) => a.displayOrder - b.displayOrder);
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<section
|
|
style={{ background: bg, borderBottom: `1px solid ${border}` }}
|
|
className="px-8 py-14 md:px-14"
|
|
>
|
|
<Loader className="py-8" />
|
|
</section>
|
|
);
|
|
}
|
|
|
|
if (partners.length === 0) return null;
|
|
|
|
return (
|
|
<section
|
|
aria-label="Partners tecnológicos de Rynext"
|
|
style={{ background: bg, borderBottom: `1px solid ${border}` }}
|
|
className="px-8 py-14 md:px-14 transition-colors duration-500"
|
|
>
|
|
<motion.div
|
|
className="mx-auto max-w-5xl"
|
|
initial={{ opacity: 0, y: 14 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
|
|
>
|
|
<p
|
|
className="mb-10 text-center text-xs font-semibold uppercase tracking-[0.18em]"
|
|
style={{ color: label }}
|
|
>
|
|
Partners tecnológicos
|
|
</p>
|
|
|
|
<div className="flex flex-wrap items-center justify-center gap-8 md:gap-12">
|
|
{partners.map((p, i) => {
|
|
const inner = (
|
|
<img
|
|
src={assetUrl(p.logoUrl!)}
|
|
alt={p.name}
|
|
style={{
|
|
height: "auto",
|
|
width: "auto",
|
|
maxHeight: 150,
|
|
maxWidth: 200,
|
|
objectFit: "contain",
|
|
filter: "grayscale(1)",
|
|
opacity: 0.55,
|
|
transition: "filter 300ms, opacity 300ms",
|
|
}}
|
|
onMouseEnter={(e) => {
|
|
(e.currentTarget as HTMLImageElement).style.filter = "grayscale(0)";
|
|
(e.currentTarget as HTMLImageElement).style.opacity = "1";
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
(e.currentTarget as HTMLImageElement).style.filter = "grayscale(1)";
|
|
(e.currentTarget as HTMLImageElement).style.opacity = "0.55";
|
|
}}
|
|
/>
|
|
);
|
|
return (
|
|
<motion.div
|
|
key={p.id}
|
|
title={p.name}
|
|
initial={{ opacity: 0, scale: 0.92 }}
|
|
whileInView={{ opacity: 1, scale: 1 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.4, delay: i * 0.07, ease: [0.22, 1, 0.36, 1] }}
|
|
whileHover={{ scale: 1.06 }}
|
|
style={{ lineHeight: 1 }}
|
|
>
|
|
{p.websiteUrl
|
|
? <a href={p.websiteUrl} target="_blank" rel="noopener noreferrer">{inner}</a>
|
|
: inner}
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</div>
|
|
</motion.div>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
export const Partners = (props: ThemeProps) => {
|
|
const [mounted, setMounted] = useState(false);
|
|
useEffect(() => setMounted(true), []);
|
|
if (!mounted) return null;
|
|
return <PartnersInner {...props} />;
|
|
};
|