180 lines
10 KiB
TypeScript
180 lines
10 KiB
TypeScript
'use client';
|
|
import { useState, useEffect } from 'react';
|
|
import { motion } from 'framer-motion';
|
|
import Loader from '../../components/Loader';
|
|
import { useTeam, groupByDepartment } from '../../services/team';
|
|
import { valores, porQueRynext } from '../../data/sobreNosotrosData';
|
|
|
|
const TEAM_IMAGE = 'https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=1200&q=80';
|
|
|
|
function SobreNosotrosContent() {
|
|
const { data: members, isLoading: loadingTeam } = useTeam();
|
|
const departments = groupByDepartment(members ?? []);
|
|
|
|
useEffect(() => {
|
|
document.title = 'Sobre Nosotros | Rynext Technologies';
|
|
}, []);
|
|
|
|
return (
|
|
<main id="main-content">
|
|
|
|
{/* Hero */}
|
|
<section
|
|
style={{ background: '#ffffff', borderBottom: '1px solid #dddbd5', paddingTop: '140px', paddingBottom: '100px' }}
|
|
className="px-8 md:px-14"
|
|
>
|
|
<div className="mx-auto max-w-7xl grid gap-16 lg:grid-cols-2 lg:items-center">
|
|
<div>
|
|
<motion.h1
|
|
className="text-display mb-8"
|
|
style={{ color: '#0a0a0a' }}
|
|
initial="hidden" whileInView="visible" viewport={{ once: true }}
|
|
variants={{ hidden: { opacity: 0, y: 32 }, visible: { opacity: 1, y: 0, transition: { duration: 0.7, delay: 0.1, ease: [0.22, 1, 0.36, 1] } } }}
|
|
>
|
|
Software 100%{' '}
|
|
<span style={{ position: 'relative', display: 'inline-block' }}>
|
|
<span style={{ color: '#3b82f6' }}>Mexicano</span>
|
|
<svg viewBox="0 0 200 12" preserveAspectRatio="none" aria-hidden="true"
|
|
style={{ position: 'absolute', bottom: -4, left: 0, width: '100%', height: 12 }}>
|
|
<path d="M2 8 C50 2, 150 2, 198 8" stroke="#3b82f6" strokeWidth="3" strokeLinecap="round" fill="none" />
|
|
</svg>
|
|
</span>{' '}
|
|
de clase mundial.
|
|
</motion.h1>
|
|
<motion.p className="text-lg leading-relaxed" style={{ color: '#6a6866' }}
|
|
initial="hidden" whileInView="visible" viewport={{ once: true }}
|
|
variants={{ hidden: { opacity: 0, y: 24 }, visible: { opacity: 1, y: 0, transition: { duration: 0.6, delay: 0.2, ease: [0.22, 1, 0.36, 1] } } }}>
|
|
Rynext Technologies nació de una convicción: México tiene el talento para construir
|
|
software empresarial que compita con cualquier firma en el mundo. No adaptamos
|
|
herramientas extranjeras diseñamos sistemas propios, con las tecnologías más
|
|
actuales, para la realidad operativa de los negocios mexicanos.
|
|
</motion.p>
|
|
</div>
|
|
|
|
<motion.div initial="hidden" whileInView="visible" viewport={{ once: true }}
|
|
variants={{ hidden: { opacity: 0, x: 24 }, visible: { opacity: 1, x: 0, transition: { duration: 0.7, delay: 0.15, ease: [0.22, 1, 0.36, 1] } } }}
|
|
style={{ position: 'relative' }}>
|
|
<div style={{ position: 'absolute', top: 16, left: -16, width: '100%', height: '100%', border: '3px solid #3b82f6', borderRadius: 2, zIndex: 0 }} />
|
|
<img src={TEAM_IMAGE} alt="Equipo Rynext Technologies"
|
|
style={{ position: 'relative', zIndex: 1, width: '100%', aspectRatio: '4/3', objectFit: 'cover', display: 'block', clipPath: 'polygon(0 0, 100% 0, 100% 88%, 94% 100%, 0 100%)' }}
|
|
/>
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Por qué Rynext */}
|
|
<section style={{ background: '#f5f5f3', borderBottom: '1px solid #dddbd5', padding: '100px 0' }} className="px-8 md:px-14">
|
|
<div className="mx-auto max-w-7xl">
|
|
<motion.h2 className="text-display mb-20" style={{ color: '#0a0a0a', maxWidth: '22ch' }}
|
|
initial="hidden" whileInView="visible" viewport={{ once: true }}
|
|
variants={{ hidden: { opacity: 0, y: 28 }, visible: { opacity: 1, y: 0, transition: { duration: 0.7, ease: [0.22, 1, 0.36, 1] } } }}>
|
|
¿Por qué <span style={{ color: '#3b82f6' }}>Rynext Technologies?</span>
|
|
</motion.h2>
|
|
<div className="flex flex-col divide-y" style={{ borderTop: '1px solid #dddbd5', borderBottom: '1px solid #dddbd5' }}>
|
|
{porQueRynext.map((item, i) => (
|
|
<motion.div key={i}
|
|
initial="hidden" whileInView="visible" viewport={{ once: true }}
|
|
variants={{ hidden: { opacity: 0, y: 16 }, visible: { opacity: 1, y: 0, transition: { duration: 0.5, delay: i * 0.08, ease: [0.22, 1, 0.36, 1] } } }}
|
|
className="grid py-10 md:grid-cols-[80px_1fr_2fr] gap-6 items-start"
|
|
style={{ borderColor: '#dddbd5' }}>
|
|
<span className="font-display font-black" style={{ fontSize: 48, lineHeight: 1, color: '#3b82f6', letterSpacing: '-0.04em' }}>{item.num}</span>
|
|
<h3 className="font-display font-bold text-xl" style={{ color: '#0a0a0a' }}>{item.titulo}</h3>
|
|
<p className="text-base leading-relaxed" style={{ color: '#6a6866', maxWidth: '52ch' }}>{item.desc}</p>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Valores */}
|
|
<section style={{ background: '#ffffff', borderBottom: '1px solid #dddbd5', padding: '100px 0' }} className="px-8 md:px-14">
|
|
<div className="mx-auto max-w-7xl">
|
|
<motion.h2 className="text-headline mb-16" style={{ color: '#0a0a0a' }}
|
|
initial="hidden" whileInView="visible" viewport={{ once: true }}
|
|
variants={{ hidden: { opacity: 0, y: 28 }, visible: { opacity: 1, y: 0, transition: { duration: 0.6, delay: 0.1, ease: [0.22, 1, 0.36, 1] } } }}>
|
|
Los principios que guían cada proyecto.
|
|
</motion.h2>
|
|
<div className="grid gap-8 md:grid-cols-5">
|
|
{valores.map((v, i) => (
|
|
<motion.div key={i}
|
|
initial="hidden" whileInView="visible" viewport={{ once: true }}
|
|
variants={{ hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0, transition: { duration: 0.5, delay: i * 0.08, ease: [0.22, 1, 0.36, 1] } } }}
|
|
style={{ borderTop: '3px solid #3b82f6', paddingTop: 24 }}>
|
|
<span className="font-display font-black block mb-4" style={{ fontSize: 48, lineHeight: 1, color: '#3b82f6', letterSpacing: '-0.04em' }}>{v.num}</span>
|
|
<h3 className="font-display font-bold text-base mb-3" style={{ color: '#0a0a0a' }}>{v.titulo}</h3>
|
|
<p className="text-sm leading-relaxed" style={{ color: '#6a6866' }}>{v.desc}</p>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Equipo */}
|
|
<section style={{ background: '#f5f5f3', borderBottom: '1px solid #dddbd5', padding: '100px 0' }} className="px-8 md:px-14">
|
|
<div className="mx-auto max-w-7xl">
|
|
<motion.h2 className="text-headline mb-16" style={{ color: '#0a0a0a' }}
|
|
initial={{ opacity: 0, y: 24 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }}
|
|
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}>
|
|
El equipo detrás del código.
|
|
</motion.h2>
|
|
|
|
{loadingTeam ? (
|
|
<Loader className="py-16" />
|
|
) : departments.length === 0 ? (
|
|
<p className="text-sm" style={{ color: '#aaa8a4' }}>Sin miembros registrados.</p>
|
|
) : (
|
|
<div className="flex flex-col gap-14">
|
|
{departments.map((dept, di) => (
|
|
<motion.div key={dept.name}
|
|
initial={{ opacity: 0, y: 20 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }}
|
|
transition={{ duration: 0.5, delay: di * 0.08, ease: [0.22, 1, 0.36, 1] }}>
|
|
{/* Dept header */}
|
|
<div className="flex items-center gap-3 mb-0">
|
|
<span style={{ width: 3, height: 16, background: '#3b82f6', borderRadius: 99, flexShrink: 0, display: 'block' }} />
|
|
<p className="text-xs font-semibold uppercase tracking-widest" style={{ color: '#6a6866' }}>
|
|
{dept.name}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Hierarchy connector */}
|
|
<div style={{ position: 'relative', paddingLeft: 20, marginLeft: 1 }}>
|
|
{/* Vertical line */}
|
|
<span style={{ position: 'absolute', left: 0, top: 0, bottom: 24, width: 1, background: '#dddbd5' }} />
|
|
{/* Horizontal branch */}
|
|
<span style={{ position: 'absolute', left: 0, top: 24, width: 16, height: 1, background: '#dddbd5' }} />
|
|
|
|
<div className="grid gap-3 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 pt-6">
|
|
{dept.members.map((m, mi) => (
|
|
<motion.div key={m.id}
|
|
initial={{ opacity: 0, y: 12 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }}
|
|
transition={{ duration: 0.4, delay: mi * 0.05, ease: [0.22, 1, 0.36, 1] }}
|
|
style={{ background: '#ffffff', borderRadius: 6, padding: '20px', display: 'flex', alignItems: 'center', gap: 14, boxShadow: '0 1px 3px rgba(0,0,0,0.07)' }}>
|
|
<div style={{ width: 44, height: 44, borderRadius: '50%', background: 'linear-gradient(135deg,#3b82f6,#1d4ed8)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
|
|
<span style={{ color: '#fff', fontWeight: 700, fontSize: 14, letterSpacing: '0.02em' }}>{m.firstName[0]}{m.lastName[0]}</span>
|
|
</div>
|
|
<div style={{ minWidth: 0 }}>
|
|
<p className="font-display font-bold text-sm" style={{ color: '#0a0a0a', lineHeight: 1.3, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{m.firstName} {m.lastName}</p>
|
|
{m.positionName && <p className="text-xs mt-0.5" style={{ color: '#9ca3af' }}>{m.positionName}</p>}
|
|
</div>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</section>
|
|
|
|
</main>
|
|
);
|
|
}
|
|
|
|
export function SobreNosotrosPage() {
|
|
const [mounted, setMounted] = useState(false);
|
|
useEffect(() => setMounted(true), []);
|
|
if (!mounted) return null;
|
|
return <SobreNosotrosContent />;
|
|
}
|