cambios
This commit is contained in:
1 parent
9dfced04f1
commit
d7f584059e
12 files changed
+524
-30
No files matched your search
+34
-18
@@ -1,23 +1,33 @@
|
||||
'use client';
|
||||
import { Suspense } from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { Hero } from '../sections/Hero';
|
||||
import { Problem } from '../sections/Problem';
|
||||
import { Machinery } from '../sections/Machinery';
|
||||
import { Showcase } from '../sections/Showcase';
|
||||
import { PlatformAdvantage } from '../sections/PlatformAdvantage';
|
||||
import { Services } from '../sections/Services';
|
||||
import { Testimonial } from '../sections/Testimonial';
|
||||
import { Anatomy } from '../sections/Anatomy';
|
||||
import { Process } from '../sections/Process';
|
||||
import { Principles } from '../sections/Principles';
|
||||
import { FAQ } from '../sections/FAQ';
|
||||
import { CtaBanner } from '../sections/CtaBanner';
|
||||
import { ContactSection } from '../sections/ContactSection';
|
||||
"use client";
|
||||
import { Suspense } from "react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { Hero } from "../sections/Hero";
|
||||
import { Problem } from "../sections/Problem";
|
||||
import { Machinery } from "../sections/Machinery";
|
||||
import { Showcase } from "../sections/Showcase";
|
||||
import { PlatformAdvantage } from "../sections/PlatformAdvantage";
|
||||
import { Services } from "../sections/Services";
|
||||
import { Testimonial } from "../sections/Testimonial";
|
||||
import { Anatomy } from "../sections/Anatomy";
|
||||
import { Process } from "../sections/Process";
|
||||
import { Principles } from "../sections/Principles";
|
||||
import { FAQ } from "../sections/FAQ";
|
||||
import { CtaBanner } from "../sections/CtaBanner";
|
||||
import { ContactSection } from "../sections/ContactSection";
|
||||
|
||||
const Clients = dynamic(
|
||||
() => import('../sections/Clients').then(m => ({ default: m.Clients })),
|
||||
{ ssr: false }
|
||||
() => import("../sections/Clients").then((m) => ({ default: m.Clients })),
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
const Partners = dynamic(
|
||||
() => import("../sections/Partners").then((m) => ({ default: m.Partners })),
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
const Portfolio = dynamic(
|
||||
() => import("../sections/Portfolio").then((m) => ({ default: m.Portfolio })),
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
export function HomePage() {
|
||||
@@ -30,6 +40,9 @@ export function HomePage() {
|
||||
<Problem isNavyBg={false} />
|
||||
<Machinery isNavyBg={false} />
|
||||
<Showcase isNavyBg={false} />
|
||||
<Suspense fallback={null}>
|
||||
<Portfolio isNavyBg={false} />
|
||||
</Suspense>
|
||||
<PlatformAdvantage isNavyBg={false} />
|
||||
<Services isNavyBg={false} />
|
||||
<Testimonial isNavyBg={false} />
|
||||
@@ -37,6 +50,9 @@ export function HomePage() {
|
||||
<Process isNavyBg={false} />
|
||||
<Principles isNavyBg={false} />
|
||||
<FAQ isNavyBg={false} />
|
||||
<Suspense fallback={null}>
|
||||
<Partners isNavyBg={false} />
|
||||
</Suspense>
|
||||
<CtaBanner isNavyBg={false} />
|
||||
<ContactSection isNavyBg={false} />
|
||||
</main>
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
'use client';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import Loader from '../../components/Loader';
|
||||
import { usePortfolio } from '../../services/portfolio';
|
||||
import { assetUrl } from '../../services/api';
|
||||
|
||||
const bg = '#f9f9f7';
|
||||
const text = '#0a0a0a';
|
||||
const sub = '#6a6866';
|
||||
const border = 'rgba(0,0,0,0.08)';
|
||||
const card = '#ffffff';
|
||||
const tagBg = 'rgba(0,0,0,0.05)';
|
||||
|
||||
function PortafolioContent() {
|
||||
const { data, isLoading } = usePortfolio();
|
||||
const projects = data ?? [];
|
||||
|
||||
if (isLoading) return <Loader className="py-32" />;
|
||||
|
||||
return (
|
||||
<main id="main-content">
|
||||
{/* Hero */}
|
||||
<section
|
||||
style={{ background: '#ffffff', borderBottom: `1px solid ${border}`, paddingTop: 140, paddingBottom: 80 }}
|
||||
className="px-8 md:px-14"
|
||||
>
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 24 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.65, ease: [0.22, 1, 0.36, 1] }}
|
||||
>
|
||||
<span className="mb-3 block text-xs font-semibold uppercase tracking-[0.14em]" style={{ color: '#3b82f6' }}>
|
||||
Casos de éxito
|
||||
</span>
|
||||
<h1 className="text-display mb-6" style={{ color: text, maxWidth: '22ch' }}>
|
||||
Construimos el sistema.{' '}
|
||||
<span style={{ color: '#3b82f6' }}>Tú operas el negocio.</span>
|
||||
</h1>
|
||||
<p className="max-w-2xl text-lg leading-relaxed" style={{ color: sub }}>
|
||||
Proyectos reales, resultados medibles. Cada implementación parte de entender la operación antes de escribir una sola línea de código.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Grid */}
|
||||
<section style={{ background: bg }} className="px-8 py-20 md:px-14">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
{projects.length === 0 ? (
|
||||
<p className="text-center py-20 text-sm" style={{ color: sub }}>Próximamente casos de éxito.</p>
|
||||
) : (
|
||||
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{projects.map((p, i) => {
|
||||
const cover = p.images.find((img) => img.isCover) ?? p.images.sort((a, b) => a.order - b.order)[0];
|
||||
return (
|
||||
<motion.article
|
||||
key={p.id}
|
||||
initial={{ opacity: 0, y: 24 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-40px' }}
|
||||
transition={{ duration: 0.55, delay: i * 0.08, ease: [0.22, 1, 0.36, 1] }}
|
||||
style={{
|
||||
borderRadius: 14,
|
||||
border: `1px solid ${border}`,
|
||||
background: card,
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
{/* Cover */}
|
||||
<div style={{ aspectRatio: '16/9', overflow: 'hidden', background: 'rgba(0,0,0,0.03)', borderBottom: `1px solid ${border}` }}>
|
||||
{cover ? (
|
||||
<img
|
||||
src={assetUrl(cover.url)}
|
||||
alt={p.title}
|
||||
style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
|
||||
/>
|
||||
) : (
|
||||
<div style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke={sub} strokeWidth="1.5">
|
||||
<rect x="3" y="3" width="18" height="18" rx="2" />
|
||||
<circle cx="8.5" cy="8.5" r="1.5" />
|
||||
<path d="m21 15-5-5L5 21" />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ padding: '24px 24px 28px', display: 'flex', flexDirection: 'column', flex: 1 }}>
|
||||
{p.clientCompanyName && (
|
||||
<span className="text-xs font-semibold uppercase tracking-wider mb-2 block" style={{ color: '#3b82f6' }}>
|
||||
{p.clientCompanyName}
|
||||
</span>
|
||||
)}
|
||||
<h2 className="font-display font-bold mb-3" style={{ fontSize: '1.1rem', color: text, letterSpacing: '-0.01em' }}>
|
||||
{p.title}
|
||||
</h2>
|
||||
{p.publicSummary && (
|
||||
<p className="text-sm leading-relaxed mb-5" style={{ color: sub }}>
|
||||
{p.publicSummary}
|
||||
</p>
|
||||
)}
|
||||
{p.technologies.length > 0 && (
|
||||
<div className="flex flex-wrap gap-2 mt-auto">
|
||||
{p.technologies.map((t) => (
|
||||
<span
|
||||
key={t.id}
|
||||
style={{
|
||||
fontSize: 10.5,
|
||||
fontWeight: 600,
|
||||
padding: '3px 9px',
|
||||
borderRadius: 99,
|
||||
background: tagBg,
|
||||
color: t.color ?? sub,
|
||||
letterSpacing: '0.01em',
|
||||
}}
|
||||
>
|
||||
{t.name}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</motion.article>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export function PortafolioPage() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
useEffect(() => setMounted(true), []);
|
||||
if (!mounted) return (
|
||||
<div className="flex min-h-screen items-center justify-center" style={{ background: bg }}>
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
return <PortafolioContent />;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import Loader from '../../components/Loader';
|
||||
|
||||
export default function Loading() {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center" style={{ background: '#f9f9f7' }}>
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { PortafolioPage } from './PortafolioPage';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Portafolio | Rynext Technologies',
|
||||
description: 'Casos de éxito reales. Proyectos que transformaron operaciones empresariales con software diseñado a medida.',
|
||||
alternates: { canonical: 'https://rynext.com.mx/portafolio' },
|
||||
};
|
||||
|
||||
export default function Page() {
|
||||
return <PortafolioPage />;
|
||||
}
|
||||
Reference in new issue
Block a user