cambios
This commit is contained in:
1 parent
794a659369
commit
5f99b65611
349 files changed
+32252
-2180
No files matched your search
@@ -0,0 +1,9 @@
|
|||||||
|
<!-- BEGIN:nextjs-agent-rules -->
|
||||||
|
|
||||||
|
# This is NOT the Next.js you know
|
||||||
|
|
||||||
|
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
|
||||||
|
|
||||||
|
This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
|
||||||
|
|
||||||
|
<!-- END:nextjs-agent-rules -->
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://ui.shadcn.com/schema.json",
|
||||||
|
"style": "default",
|
||||||
|
"rsc": true,
|
||||||
|
"tsx": true,
|
||||||
|
"tailwind": {
|
||||||
|
"config": "",
|
||||||
|
"css": "src/app/globals.css",
|
||||||
|
"baseColor": "slate",
|
||||||
|
"cssVariables": true,
|
||||||
|
"prefix": ""
|
||||||
|
},
|
||||||
|
"aliases": {
|
||||||
|
"components": "@/components",
|
||||||
|
"utils": "@/lib/utils",
|
||||||
|
"ui": "@/components/ui",
|
||||||
|
"lib": "@/lib",
|
||||||
|
"hooks": "@/hooks"
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/types/routes.d.ts";
|
import "./.next/dev/types/routes.d.ts";
|
||||||
import "./.next/types/root-params.d.ts";
|
import "./.next/dev/types/root-params.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
@@ -2,8 +2,17 @@ import type { NextConfig } from 'next';
|
|||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
|
devIndicators: false,
|
||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
trailingSlash: true,
|
trailingSlash: true,
|
||||||
|
images: {
|
||||||
|
remotePatterns: [
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'images.unsplash.com',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
Generated
+2000
-46
File diff suppressed because it is too large.
Load diff
+21
-1
@@ -9,14 +9,34 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/lang-html": "^6.4.12",
|
||||||
|
"@codemirror/theme-one-dark": "^6.1.3",
|
||||||
|
"@dnd-kit/core": "^6.3.1",
|
||||||
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
|
"@iconify/react": "^6.0.2",
|
||||||
|
"@radix-ui/react-dialog": "^1.1.23",
|
||||||
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
|
"@radix-ui/react-label": "^2.1.15",
|
||||||
|
"@radix-ui/react-navigation-menu": "^1.2.22",
|
||||||
|
"@radix-ui/react-slot": "^1.3.3",
|
||||||
"@tanstack/react-query": "^5.102.4",
|
"@tanstack/react-query": "^5.102.4",
|
||||||
|
"@tanstack/react-query-devtools": "^5.104.0",
|
||||||
|
"@uiw/react-codemirror": "^4.25.12",
|
||||||
|
"axios": "^1.20.0",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^12.43.0",
|
"framer-motion": "^12.43.0",
|
||||||
"lucide-react": "^1.28.0",
|
"lucide-react": "^1.28.0",
|
||||||
"next": "^16.3.3",
|
"next": "^16.3.3",
|
||||||
"react": "^19.2.8",
|
"react": "^19.2.8",
|
||||||
"react-dom": "^19.2.8",
|
"react-dom": "^19.2.8",
|
||||||
"react-icons": "^5.7.0",
|
"react-icons": "^5.7.0",
|
||||||
"tailwindcss": "^4.3.3"
|
"recharts": "^3.10.1",
|
||||||
|
"sonner": "^2.0.8",
|
||||||
|
"tailwind-merge": "^3.7.0",
|
||||||
|
"tailwindcss": "^4.3.3",
|
||||||
|
"zod": "^4.6.5",
|
||||||
|
"zustand": "^5.0.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.3.3",
|
"@tailwindcss/postcss": "^4.3.3",
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,568 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{display:none;}
|
||||||
|
.st1{stroke:#000000;stroke-miterlimit:10;}
|
||||||
|
.st2{display:inline;fill:#00B5FF;}
|
||||||
|
.st3{display:inline;fill:#008EFF;}
|
||||||
|
.st4{display:inline;fill:#0063EE;}
|
||||||
|
.st5{display:inline;}
|
||||||
|
.st6{fill:#00B5FF;}
|
||||||
|
.st7{fill:#008EFF;}
|
||||||
|
.st8{fill:#0063EE;}
|
||||||
|
.st9{display:none;fill:#FFFFFF;}
|
||||||
|
.st10{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Capa_2" class="st0">
|
||||||
|
<polygon points="374.5,793.5 451.5,839.5 451.5,497.5 374.5,448.23 "/>
|
||||||
|
<polygon class="st1" points="221.5,701.5 294.5,746.5 294.5,366.5 221.5,320.23 "/>
|
||||||
|
<path d="M294.5,366.5l242-148l102,68l-264,161.73l77,49.27l223-133c0,0,48-35,43-82c0,0-2-48-33-62l-150-90l-313,189.73
|
||||||
|
L294.5,366.5z"/>
|
||||||
|
<polygon class="st2" points="464,846.5 464,728.4 535,790.5 553,777.5 631,830.5 539,890.5 "/>
|
||||||
|
<polyline class="st3" points="848,702 541,506 464,558 778,747 "/>
|
||||||
|
<polygon class="st4" points="464,558 464,503.53 500,478 541,506 "/>
|
||||||
|
<polygon class="st3" points="778,278 778,747 848,702 848,321.43 "/>
|
||||||
|
<path class="st5" d="M374.5,793.5l77,46l0-342l223-133c0,0,87.22-69.98,15.86-140.74L534.5,130.5l-313,189.73l0,381.27l73,45l0-380
|
||||||
|
l242-148l102,68l-264,161.73L374.5,793.5z"/>
|
||||||
|
</g>
|
||||||
|
<g id="Capa_1">
|
||||||
|
|
||||||
|
<image style="display:none;overflow:visible;" width="242" height="207" xlink:href="data:image/png;base64,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
|
||||||
|
ghSvTv//AAE/eVjcr77lAAAAAElFTkSuQmCC" transform="matrix(4.1322 0 0 4.1322 0 46)">
|
||||||
|
</image>
|
||||||
|
<rect class="st0" width="1000" height="1000"/>
|
||||||
|
<polygon class="st6" points="464,846.5 464,728.4 535,790.5 553,777.5 631,830.5 539,890.5 "/>
|
||||||
|
<polyline class="st7" points="847.97,702.06 541.04,505.96 464.02,557.94 777.96,747.04 "/>
|
||||||
|
<polygon class="st8" points="464,558 464,503.53 500,478 541,506 "/>
|
||||||
|
<polygon class="st7" points="778,278 778,747 848,702 848,321.43 "/>
|
||||||
|
<path class="st9" d="M294.5,366.5l242-148l102,68l-264,161.73l77,49.27l223-133c0,0,48-35,43-82c0,0-2-48-33-62l-150-90
|
||||||
|
l-313,189.73L294.5,366.5z"/>
|
||||||
|
<polygon class="st9" points="221.5,701.5 294.5,746.5 294.5,366.5 221.5,320.23 "/>
|
||||||
|
<polygon class="st9" points="374.5,793.5 451.5,839.5 451.5,497.5 374.5,448.23 "/>
|
||||||
|
<path class="st10" d="M374.5,793.5l77,46l0-342l223-133c0,0,87.22-69.98,15.86-140.74L534.5,130.5l-313,189.73l0,381.27l73,45
|
||||||
|
l0-380l242-148l102,68l-264,161.73L374.5,793.5z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 42 KiB |
@@ -0,0 +1,568 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{display:none;}
|
||||||
|
.st1{display:none;stroke:#000000;stroke-miterlimit:10;}
|
||||||
|
.st2{fill:#00B5FF;}
|
||||||
|
.st3{fill:#008EFF;}
|
||||||
|
.st4{fill:#0063EE;}
|
||||||
|
.st5{display:inline;}
|
||||||
|
.st6{display:inline;fill:#00B5FF;}
|
||||||
|
.st7{display:inline;fill:#008EFF;}
|
||||||
|
.st8{display:inline;fill:#0063EE;}
|
||||||
|
.st9{fill:#FFFFFF;}
|
||||||
|
.st10{display:inline;fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Capa_2">
|
||||||
|
<polygon class="st0" points="374.5,793.5 451.5,839.5 451.5,497.5 374.5,448.23 "/>
|
||||||
|
<polygon class="st1" points="221.5,701.5 294.5,746.5 294.5,366.5 221.5,320.23 "/>
|
||||||
|
<path class="st0" d="M294.5,366.5l242-148l102,68l-264,161.73l77,49.27l223-133c0,0,48-35,43-82c0,0-2-48-33-62l-150-90
|
||||||
|
l-313,189.73L294.5,366.5z"/>
|
||||||
|
<polygon class="st2" points="464,846.5 464,728.4 535,790.5 553,777.5 631,830.5 539,890.5 "/>
|
||||||
|
<polyline class="st3" points="848,702 541,506 464,558 778,747 "/>
|
||||||
|
<polygon class="st4" points="464,558 464,503.53 500,478 541,506 "/>
|
||||||
|
<polygon class="st3" points="778,278 778,747 848,702 848,321.43 "/>
|
||||||
|
<path d="M374.5,793.5l77,46l0-342l223-133c0,0,87.22-69.98,15.86-140.74L534.5,130.5l-313,189.73l0,381.27l73,45l0-380l242-148
|
||||||
|
l102,68l-264,161.73L374.5,793.5z"/>
|
||||||
|
</g>
|
||||||
|
<g id="Capa_1" class="st0">
|
||||||
|
|
||||||
|
<image style="overflow:visible;" width="242" height="207" xlink:href="data:image/png;base64,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
|
||||||
|
ghSvTv//AAE/eVjcr77lAAAAAElFTkSuQmCC" transform="matrix(4.1322 0 0 4.1322 0 46)">
|
||||||
|
</image>
|
||||||
|
<rect class="st5" width="1000" height="1000"/>
|
||||||
|
<polygon class="st6" points="464,846.5 464,728.4 535,790.5 553,777.5 631,830.5 539,890.5 "/>
|
||||||
|
<polyline class="st7" points="847.97,702.06 541.04,505.96 464.02,557.94 777.96,747.04 "/>
|
||||||
|
<polygon class="st8" points="464,558 464,503.53 500,478 541,506 "/>
|
||||||
|
<polygon class="st7" points="778,278 778,747 848,702 848,321.43 "/>
|
||||||
|
<path class="st9" d="M294.5,366.5l242-148l102,68l-264,161.73l77,49.27l223-133c0,0,48-35,43-82c0,0-2-48-33-62l-150-90
|
||||||
|
l-313,189.73L294.5,366.5z"/>
|
||||||
|
<polygon class="st9" points="221.5,701.5 294.5,746.5 294.5,366.5 221.5,320.23 "/>
|
||||||
|
<polygon class="st9" points="374.5,793.5 451.5,839.5 451.5,497.5 374.5,448.23 "/>
|
||||||
|
<path class="st10" d="M374.5,793.5l77,46l0-342l223-133c0,0,87.22-69.98,15.86-140.74L534.5,130.5l-313,189.73l0,381.27l73,45
|
||||||
|
l0-380l242-148l102,68l-264,161.73L374.5,793.5z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 42 KiB |
-184
@@ -1,184 +0,0 @@
|
|||||||
.counter {
|
|
||||||
font-size: 16px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
color: var(--accent);
|
|
||||||
background: var(--accent-bg);
|
|
||||||
border: 2px solid transparent;
|
|
||||||
transition: border-color 0.3s;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: var(--accent-border);
|
|
||||||
}
|
|
||||||
&:focus-visible {
|
|
||||||
outline: 2px solid var(--accent);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.base,
|
|
||||||
.framework,
|
|
||||||
.vite {
|
|
||||||
inset-inline: 0;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.base {
|
|
||||||
width: 170px;
|
|
||||||
position: relative;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.framework,
|
|
||||||
.vite {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.framework {
|
|
||||||
z-index: 1;
|
|
||||||
top: 34px;
|
|
||||||
height: 28px;
|
|
||||||
transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg)
|
|
||||||
scale(1.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vite {
|
|
||||||
z-index: 0;
|
|
||||||
top: 107px;
|
|
||||||
height: 26px;
|
|
||||||
width: auto;
|
|
||||||
transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg)
|
|
||||||
scale(0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#center {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 25px;
|
|
||||||
place-content: center;
|
|
||||||
place-items: center;
|
|
||||||
flex-grow: 1;
|
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
padding: 32px 20px 24px;
|
|
||||||
gap: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#next-steps {
|
|
||||||
display: flex;
|
|
||||||
border-top: 1px solid var(--border);
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
flex: 1 1 0;
|
|
||||||
padding: 32px;
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
padding: 24px 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
flex-direction: column;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#docs {
|
|
||||||
border-right: 1px solid var(--border);
|
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
border-right: none;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#next-steps ul {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
margin: 32px 0 0;
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--text-h);
|
|
||||||
font-size: 16px;
|
|
||||||
border-radius: 6px;
|
|
||||||
background: var(--social-bg);
|
|
||||||
display: flex;
|
|
||||||
padding: 6px 12px;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: box-shadow 0.3s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
box-shadow: var(--shadow);
|
|
||||||
}
|
|
||||||
.button-icon {
|
|
||||||
height: 18px;
|
|
||||||
width: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
margin-top: 20px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
li {
|
|
||||||
flex: 1 1 calc(50% - 8px);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
width: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#spacer {
|
|
||||||
height: 88px;
|
|
||||||
border-top: 1px solid var(--border);
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ticks {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&::before,
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: -4.5px;
|
|
||||||
border: 5px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
left: 0;
|
|
||||||
border-left-color: var(--border);
|
|
||||||
}
|
|
||||||
&::after {
|
|
||||||
right: 0;
|
|
||||||
border-right-color: var(--border);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
'use client';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
import { Button } from '@/app/(landing)/components/ui/button';
|
||||||
|
import {
|
||||||
|
Empty,
|
||||||
|
EmptyContent,
|
||||||
|
EmptyDescription,
|
||||||
|
EmptyHeader,
|
||||||
|
EmptyTitle,
|
||||||
|
} from '@/app/(landing)/components/ui/empty';
|
||||||
|
|
||||||
|
export function NotFoundPage() {
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = '404 — Página no encontrada | Rynext Technologies';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main
|
||||||
|
id="main-content"
|
||||||
|
className="relative flex w-full items-center justify-center px-8 pb-24 pt-40"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute -top-16 -left-20 h-[24rem] w-[24rem] rounded-full blur-[110px]"
|
||||||
|
style={{ background: 'rgba(59,130,246,0.16)' }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute -top-16 -right-20 h-[24rem] w-[24rem] rounded-full blur-[110px]"
|
||||||
|
style={{ background: 'rgba(139,92,246,0.16)' }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Empty className="relative border-none">
|
||||||
|
<EmptyHeader>
|
||||||
|
<EmptyTitle
|
||||||
|
className="font-display font-black"
|
||||||
|
style={{ fontSize: 'clamp(6rem, 20vw, 10rem)', lineHeight: 1, letterSpacing: '-0.04em', color: 'var(--foreground)' }}
|
||||||
|
>
|
||||||
|
404
|
||||||
|
</EmptyTitle>
|
||||||
|
<EmptyDescription style={{ color: 'var(--muted-foreground)' }}>
|
||||||
|
La página que buscas no existe o fue movida.
|
||||||
|
</EmptyDescription>
|
||||||
|
</EmptyHeader>
|
||||||
|
<EmptyContent>
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<Button asChild>
|
||||||
|
<Link href="/">
|
||||||
|
<Icon icon="ph:house" className="mr-2 size-4" />
|
||||||
|
Ir al inicio
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
<Button asChild variant="outline">
|
||||||
|
<Link href="/portafolio">
|
||||||
|
<Icon icon="ph:compass" className="mr-2 size-4" />
|
||||||
|
Ver portafolio
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</EmptyContent>
|
||||||
|
</Empty>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
"use client";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
|
import { useBlogPosts } from '@/app/(landing)/blog/services/blog';
|
||||||
|
|
||||||
|
const fadeUp = {
|
||||||
|
hidden: { opacity: 0, y: 28 },
|
||||||
|
visible: {
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] as const },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function BlogContent() {
|
||||||
|
const { data, isLoading } = useBlogPosts();
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = "Blog | Rynext Technologies";
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const posts = (data ?? []).map((p) => ({
|
||||||
|
id: p.id,
|
||||||
|
category: p.category.toUpperCase(),
|
||||||
|
title: p.title,
|
||||||
|
summary: p.summary,
|
||||||
|
publishedAt: p.publishedAt,
|
||||||
|
imageUrl: p.imageUrl,
|
||||||
|
slug: p.slug,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main id="main-content">
|
||||||
|
<section
|
||||||
|
style={{
|
||||||
|
background: "var(--background)",
|
||||||
|
paddingTop: "120px",
|
||||||
|
paddingBottom: "16px",
|
||||||
|
}}
|
||||||
|
className="px-8 md:px-14"
|
||||||
|
>
|
||||||
|
<div className="mx-auto max-w-7xl text-center">
|
||||||
|
<motion.h1
|
||||||
|
className="text-2xl md:text-3xl font-bold"
|
||||||
|
style={{ color: "var(--foreground)" }}
|
||||||
|
initial="hidden"
|
||||||
|
whileInView="visible"
|
||||||
|
viewport={{ once: true }}
|
||||||
|
variants={fadeUp}
|
||||||
|
>
|
||||||
|
Artículos
|
||||||
|
</motion.h1>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section
|
||||||
|
style={{
|
||||||
|
background: "var(--background)",
|
||||||
|
padding: "0 0 100px",
|
||||||
|
minHeight: "60vh",
|
||||||
|
}}
|
||||||
|
className="px-8 md:px-14"
|
||||||
|
>
|
||||||
|
<div className="mx-auto max-w-7xl">
|
||||||
|
{isLoading ? (
|
||||||
|
<Loader className="py-20" />
|
||||||
|
) : posts.length > 0 ? (
|
||||||
|
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||||
|
{posts.map((art, i) => (
|
||||||
|
<motion.article
|
||||||
|
key={art.id}
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
whileHover={{ y: -4 }}
|
||||||
|
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 var(--border)",
|
||||||
|
background: "var(--card)",
|
||||||
|
overflow: "hidden",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
opacity: art.slug ? 1 : 0.82,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={art.slug ? `/blog/${art.slug}` : "#"}
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
textDecoration: "none",
|
||||||
|
color: "inherit",
|
||||||
|
pointerEvents: art.slug ? "auto" : "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
aspectRatio: "16/9",
|
||||||
|
overflow: "hidden",
|
||||||
|
background: "rgba(0,0,0,0.03)",
|
||||||
|
borderBottom: "1px solid var(--border)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{art.imageUrl ? (
|
||||||
|
<img
|
||||||
|
src={art.imageUrl}
|
||||||
|
alt={art.title}
|
||||||
|
style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }}
|
||||||
|
onError={(e) => {
|
||||||
|
(e.currentTarget as HTMLImageElement).style.display = "none";
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<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="var(--muted-foreground)" 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>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
padding: "24px 24px 28px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{art.category && (
|
||||||
|
<span
|
||||||
|
className="text-xs font-semibold uppercase tracking-wider mb-2 block"
|
||||||
|
style={{ color: "#3b82f6" }}
|
||||||
|
>
|
||||||
|
{art.category}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<h2
|
||||||
|
className="font-display font-bold mb-3"
|
||||||
|
style={{ fontSize: "1.1rem", color: "var(--foreground)", letterSpacing: "-0.01em" }}
|
||||||
|
>
|
||||||
|
{art.title}
|
||||||
|
</h2>
|
||||||
|
<p
|
||||||
|
className="text-sm leading-relaxed mb-5"
|
||||||
|
style={{ color: "var(--muted-foreground)", flex: 1 }}
|
||||||
|
>
|
||||||
|
{art.summary}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className="text-xs mt-auto"
|
||||||
|
style={{ color: "var(--muted-foreground)" }}
|
||||||
|
>
|
||||||
|
{art.publishedAt
|
||||||
|
? new Date(art.publishedAt).toLocaleDateString(
|
||||||
|
"es-MX",
|
||||||
|
{ day: "2-digit", month: "long", year: "numeric" },
|
||||||
|
)
|
||||||
|
: "Próximamente"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</motion.article>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="text-sm" style={{ color: "var(--muted-foreground)" }}>
|
||||||
|
Sin artículos publicados.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BlogPage() {
|
||||||
|
const [mounted, setMounted] = useState(false);
|
||||||
|
useEffect(() => setMounted(true), []);
|
||||||
|
if (!mounted) return null;
|
||||||
|
return <BlogContent />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
"use client";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useParams, useRouter } from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import { useBlogPost } from '@/app/(landing)/blog/services/blog';
|
||||||
|
import { assetUrl } from '@/app/(landing)/services/api';
|
||||||
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
|
|
||||||
|
function renderContent(content: string) {
|
||||||
|
return content.split("\n").map((line, i) => {
|
||||||
|
if (line.startsWith("# "))
|
||||||
|
return (
|
||||||
|
<h2
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
fontSize: "1.5rem",
|
||||||
|
fontWeight: 700,
|
||||||
|
color: "var(--foreground)",
|
||||||
|
marginTop: "2rem",
|
||||||
|
marginBottom: "0.5rem",
|
||||||
|
lineHeight: 1.3,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{line.slice(2)}
|
||||||
|
</h2>
|
||||||
|
);
|
||||||
|
if (line.startsWith("## "))
|
||||||
|
return (
|
||||||
|
<h3
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
fontSize: "1.15rem",
|
||||||
|
fontWeight: 600,
|
||||||
|
color: "var(--foreground)",
|
||||||
|
marginTop: "1.5rem",
|
||||||
|
marginBottom: "0.4rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{line.slice(3)}
|
||||||
|
</h3>
|
||||||
|
);
|
||||||
|
if (line.startsWith("- "))
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
color: "var(--muted-foreground)",
|
||||||
|
lineHeight: 1.8,
|
||||||
|
marginLeft: "1.2rem",
|
||||||
|
listStyleType: "disc",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{line.slice(2)}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
if (line.trim() === "") return <br key={i} />;
|
||||||
|
return (
|
||||||
|
<p
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
color: "var(--muted-foreground)",
|
||||||
|
lineHeight: 1.85,
|
||||||
|
marginBottom: "0.25rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{line}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ArticlePage() {
|
||||||
|
const params = useParams();
|
||||||
|
const router = useRouter();
|
||||||
|
const slug =
|
||||||
|
typeof params.slug === "string" ? params.slug : (params.slug?.[0] ?? "");
|
||||||
|
|
||||||
|
const { data: post, isLoading, isError } = useBlogPost(slug);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (post) document.title = `${post.title} | Blog`;
|
||||||
|
}, [post]);
|
||||||
|
|
||||||
|
if (isLoading) return <Loader className="py-40" />;
|
||||||
|
if (isError || !post) {
|
||||||
|
return (
|
||||||
|
<main
|
||||||
|
style={{
|
||||||
|
minHeight: "80vh",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
gap: 16,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
style={{
|
||||||
|
color: "var(--muted-foreground)",
|
||||||
|
fontSize: 14,
|
||||||
|
fontFamily: "monospace",
|
||||||
|
letterSpacing: "0.1em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
ARTÍCULO NO ENCONTRADO
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={() => router.push("/blog")}
|
||||||
|
style={{
|
||||||
|
color: "#3b82f6",
|
||||||
|
fontSize: 14,
|
||||||
|
textDecoration: "underline",
|
||||||
|
background: "none",
|
||||||
|
border: "none",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Volver al blog
|
||||||
|
</button>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageUrl = assetUrl(post.imageUrl);
|
||||||
|
const publishDate = post.publishedAt
|
||||||
|
? new Date(post.publishedAt).toLocaleDateString("es-MX", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main id="main-content">
|
||||||
|
{/* Hero */}
|
||||||
|
<section
|
||||||
|
style={{
|
||||||
|
background: "var(--background)",
|
||||||
|
paddingTop: "140px",
|
||||||
|
paddingBottom: "60px",
|
||||||
|
}}
|
||||||
|
className="px-8 md:px-14"
|
||||||
|
>
|
||||||
|
<div className="mx-auto" style={{ maxWidth: "780px" }}>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
>
|
||||||
|
{/* Volver */}
|
||||||
|
<Link
|
||||||
|
href="/blog"
|
||||||
|
style={{ display: "inline-flex", alignItems: "center", gap: 8, marginBottom: 20, fontFamily: "monospace", fontSize: 11, letterSpacing: "0.14em", color: "#3b82f6", textDecoration: "none" }}
|
||||||
|
>
|
||||||
|
← VOLVER AL BLOG
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{post.category && (
|
||||||
|
<div style={{ marginBottom: 20, fontFamily: "monospace", fontSize: 11, letterSpacing: "0.14em", color: "var(--muted-foreground)" }}>
|
||||||
|
{post.category.toUpperCase()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Título */}
|
||||||
|
<h1
|
||||||
|
style={{
|
||||||
|
fontSize: "clamp(1.8rem, 4vw, 2.8rem)",
|
||||||
|
fontWeight: 700,
|
||||||
|
color: "var(--foreground)",
|
||||||
|
lineHeight: 1.2,
|
||||||
|
marginBottom: 20,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{post.title}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{/* Resumen */}
|
||||||
|
{post.summary && (
|
||||||
|
<p
|
||||||
|
style={{
|
||||||
|
fontSize: "1.1rem",
|
||||||
|
color: "var(--muted-foreground)",
|
||||||
|
lineHeight: 1.7,
|
||||||
|
marginBottom: 28,
|
||||||
|
borderLeft: "3px solid var(--border)",
|
||||||
|
paddingLeft: 16,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{post.summary}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Meta */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 16,
|
||||||
|
paddingTop: 20,
|
||||||
|
borderTop: "1px solid var(--border)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{post.authorName && (
|
||||||
|
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
borderRadius: "50%",
|
||||||
|
background: "linear-gradient(135deg,#3b82f6,#6366f1)",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: 700,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{post.authorName.charAt(0).toUpperCase()}
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: 500,
|
||||||
|
color: "var(--foreground)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{post.authorName}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{publishDate && (
|
||||||
|
<>
|
||||||
|
{post.authorName && (
|
||||||
|
<span style={{ color: "var(--border)" }}>·</span>
|
||||||
|
)}
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontFamily: "monospace",
|
||||||
|
fontSize: 11,
|
||||||
|
color: "var(--muted-foreground)",
|
||||||
|
letterSpacing: "0.1em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{publishDate.toUpperCase()}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Imagen de portada */}
|
||||||
|
{imageUrl && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "var(--muted)",
|
||||||
|
borderBottom: "1px solid var(--border)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="mx-auto"
|
||||||
|
style={{ maxWidth: "1100px", padding: "0 2rem" }}
|
||||||
|
>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.98 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.15 }}
|
||||||
|
style={{
|
||||||
|
overflow: "hidden",
|
||||||
|
borderRadius: 4,
|
||||||
|
aspectRatio: "16/7",
|
||||||
|
marginTop: -1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={imageUrl}
|
||||||
|
alt={post.title}
|
||||||
|
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Contenido */}
|
||||||
|
<section
|
||||||
|
style={{ background: "var(--background)", padding: "80px 0" }}
|
||||||
|
className="px-8 md:px-14"
|
||||||
|
>
|
||||||
|
<motion.div
|
||||||
|
className="mx-auto"
|
||||||
|
style={{ maxWidth: "780px" }}
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.2 }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "var(--card)",
|
||||||
|
border: "1px solid var(--border)",
|
||||||
|
borderRadius: 4,
|
||||||
|
padding: "48px 52px",
|
||||||
|
fontSize: "1rem",
|
||||||
|
lineHeight: 1.85,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{renderContent(post.content)}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
import ArticlePage from "./ArticlePage";
|
||||||
|
import { API_URL, assetUrl } from '@/app/(landing)/services/api';
|
||||||
|
import type { BlogPost } from '@/app/(landing)/blog/services/blog';
|
||||||
|
|
||||||
|
const BASE_URL = "https://rynext.com.mx";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* null = la API respondió que el artículo no existe o no está publicado (404 real).
|
||||||
|
* undefined = no se pudo consultar la API (red, TLS local, etc.) — no es un 404,
|
||||||
|
* se deja que el cliente (ArticlePage) resuelva con su propio fetch.
|
||||||
|
*/
|
||||||
|
async function getPost(slug: string): Promise<BlogPost | null | undefined> {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API_URL}/api/blog/${slug}`, {
|
||||||
|
next: { revalidate: 3600 },
|
||||||
|
});
|
||||||
|
if (!res.ok) return null;
|
||||||
|
const post = (await res.json()) as BlogPost;
|
||||||
|
return post.isPublished ? post : null;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = { params: Promise<{ slug: string }> };
|
||||||
|
|
||||||
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||||
|
const { slug } = await params;
|
||||||
|
const post = await getPost(slug);
|
||||||
|
|
||||||
|
if (!post) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `${BASE_URL}/blog/${post.slug}`;
|
||||||
|
const image = assetUrl(post.imageUrl);
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: `${post.title} | Blog | Rynext Technologies`,
|
||||||
|
description: post.summary,
|
||||||
|
alternates: { canonical: url },
|
||||||
|
openGraph: {
|
||||||
|
title: post.title,
|
||||||
|
description: post.summary,
|
||||||
|
type: "article",
|
||||||
|
url,
|
||||||
|
publishedTime: post.publishedAt,
|
||||||
|
images: image
|
||||||
|
? [{ url: image, width: 1200, height: 630, alt: post.title }]
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary_large_image",
|
||||||
|
title: post.title,
|
||||||
|
description: post.summary,
|
||||||
|
images: image ? [image] : undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Page({ params }: Props) {
|
||||||
|
const { slug } = await params;
|
||||||
|
const post = await getPost(slug);
|
||||||
|
|
||||||
|
// Solo 404 cuando confirmamos que no existe/no está publicado; si la API
|
||||||
|
// no respondió, dejamos que ArticlePage lo resuelva del lado del cliente.
|
||||||
|
if (post === null) notFound();
|
||||||
|
|
||||||
|
return <ArticlePage />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-dvh items-center justify-center" style={{ background: 'var(--background)' }}>
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,32 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { apiFetch } from '@/app/(landing)/services/api';
|
||||||
|
|
||||||
|
export interface BlogPost {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
slug: string;
|
||||||
|
summary: string;
|
||||||
|
content: string;
|
||||||
|
category: string;
|
||||||
|
imageUrl?: string;
|
||||||
|
authorName?: string;
|
||||||
|
isPublished: boolean;
|
||||||
|
publishedAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useBlogPosts() {
|
||||||
|
return useQuery<BlogPost[]>({
|
||||||
|
queryKey: ["blog"],
|
||||||
|
queryFn: () => apiFetch<BlogPost[]>("/api/blog"),
|
||||||
|
staleTime: 1000 * 60 * 5,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useBlogPost(slug: string) {
|
||||||
|
return useQuery<BlogPost>({
|
||||||
|
queryKey: ["blog", slug],
|
||||||
|
queryFn: () => apiFetch<BlogPost>(`/api/blog/${slug}`),
|
||||||
|
staleTime: 1000 * 60 * 5,
|
||||||
|
enabled: !!slug,
|
||||||
|
});
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,39 @@
|
|||||||
|
"use client";
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
|
import { ContactProvider } from "@/app/(landing)/contexts/ContactContext";
|
||||||
|
import { useIsDark } from "@/app/(landing)/hooks/useIsDark";
|
||||||
|
import { ScrollToTop } from "./ScrollToTop";
|
||||||
|
import { Navbar } from "./Navbar";
|
||||||
|
import { Footer } from "./Footer";
|
||||||
|
import { FloatingButtons } from "./FloatingButtons";
|
||||||
|
import { CookieBanner } from "./CookieBanner";
|
||||||
|
import { MusicPlayer } from "./MusicPlayer";
|
||||||
|
|
||||||
|
const BARE_ROUTES = ["/demo-hero", "/admin"];
|
||||||
|
|
||||||
|
export const AppShell = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
const pathname = usePathname();
|
||||||
|
const isBare = BARE_ROUTES.some((route) => pathname?.startsWith(route));
|
||||||
|
const isDark = useIsDark();
|
||||||
|
|
||||||
|
if (isBare) {
|
||||||
|
return <ContactProvider>{children}</ContactProvider>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ContactProvider>
|
||||||
|
<div
|
||||||
|
className="min-h-dvh font-sans"
|
||||||
|
style={{ background: "var(--background)", overflowX: "clip", overflowY: "visible" }}
|
||||||
|
>
|
||||||
|
<ScrollToTop />
|
||||||
|
<Navbar />
|
||||||
|
{children}
|
||||||
|
<Footer isNavyBg={isDark} />
|
||||||
|
<FloatingButtons isNavyBg={isDark} setIsNavyBg={() => {}} />
|
||||||
|
<MusicPlayer />
|
||||||
|
<CookieBanner isNavyBg={isDark} />
|
||||||
|
</div>
|
||||||
|
</ContactProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
File renamed without changes.
+10
-10
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { X, Send, CheckCircle, AlertCircle, Loader2 } from 'lucide-react';
|
import { Icon } from '@iconify/react';
|
||||||
import type { ModalProps } from '@/app/types/ui';
|
import type { ModalProps } from '@/app/(landing)/types/ui';
|
||||||
|
|
||||||
const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'https://localhost:7001';
|
const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'https://localhost:7001';
|
||||||
|
|
||||||
@@ -51,12 +51,12 @@ export const ContactModal = ({ isOpen, onClose, isNavyBg }: ModalProps) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const card = isNavyBg ? '#0d1b35' : '#ffffff';
|
const card = isNavyBg ? 'var(--card)' : '#ffffff';
|
||||||
const bdr = isNavyBg ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.1)';
|
const bdr = isNavyBg ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.1)';
|
||||||
const text = isNavyBg ? '#ffffff' : '#0a0a0a';
|
const text = isNavyBg ? 'var(--foreground)' : '#0a0a0a';
|
||||||
const sub = isNavyBg ? 'rgba(255,255,255,0.45)' : '#6a6866';
|
const sub = isNavyBg ? 'rgba(255,255,255,0.45)' : '#6a6866';
|
||||||
const inputStyle: React.CSSProperties = {
|
const inputStyle: React.CSSProperties = {
|
||||||
width: '100%', borderRadius: 8, padding: '11px 14px',
|
width: '100%', borderRadius: 12, padding: '11px 14px',
|
||||||
fontSize: 14, fontFamily: 'inherit', outline: 'none',
|
fontSize: 14, fontFamily: 'inherit', outline: 'none',
|
||||||
transition: 'border-color 150ms',
|
transition: 'border-color 150ms',
|
||||||
...(isNavyBg
|
...(isNavyBg
|
||||||
@@ -91,14 +91,14 @@ export const ContactModal = ({ isOpen, onClose, isNavyBg }: ModalProps) => {
|
|||||||
style={{ background: 'rgba(0,0,0,0.06)', color: sub, border: 'none', cursor: 'pointer' }}
|
style={{ background: 'rgba(0,0,0,0.06)', color: sub, border: 'none', cursor: 'pointer' }}
|
||||||
aria-label="Cerrar"
|
aria-label="Cerrar"
|
||||||
>
|
>
|
||||||
<X size={16} />
|
<Icon icon="ph:x" width={16} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Success state */}
|
{/* Success state */}
|
||||||
{status === 'success' ? (
|
{status === 'success' ? (
|
||||||
<div className="flex flex-col items-center justify-center gap-4 px-8 py-14 text-center">
|
<div className="flex flex-col items-center justify-center gap-4 px-8 py-14 text-center">
|
||||||
<CheckCircle size={48} style={{ color: '#22c55e' }} />
|
<Icon icon="ph:check-circle" width={48} style={{ color: '#22c55e' }} />
|
||||||
<h4 className="font-display font-bold text-lg" style={{ color: text }}>
|
<h4 className="font-display font-bold text-lg" style={{ color: text }}>
|
||||||
¡Mensaje enviado!
|
¡Mensaje enviado!
|
||||||
</h4>
|
</h4>
|
||||||
@@ -187,7 +187,7 @@ export const ContactModal = ({ isOpen, onClose, isNavyBg }: ModalProps) => {
|
|||||||
|
|
||||||
{status === 'error' && (
|
{status === 'error' && (
|
||||||
<div className="flex items-center gap-2 px-4 py-3 rounded-lg" style={{ background: 'rgba(239,68,68,0.08)', border: '1px solid rgba(239,68,68,0.2)' }}>
|
<div className="flex items-center gap-2 px-4 py-3 rounded-lg" style={{ background: 'rgba(239,68,68,0.08)', border: '1px solid rgba(239,68,68,0.2)' }}>
|
||||||
<AlertCircle size={15} style={{ color: '#ef4444', flexShrink: 0 }} />
|
<Icon icon="ph:warning-circle" width={15} style={{ color: '#ef4444', flexShrink: 0 }} />
|
||||||
<p className="text-sm" style={{ color: '#ef4444' }}>
|
<p className="text-sm" style={{ color: '#ef4444' }}>
|
||||||
Hubo un error al enviar. Intenta de nuevo o escríbenos a contacto@rynext.com.mx
|
Hubo un error al enviar. Intenta de nuevo o escríbenos a contacto@rynext.com.mx
|
||||||
</p>
|
</p>
|
||||||
@@ -202,12 +202,12 @@ export const ContactModal = ({ isOpen, onClose, isNavyBg }: ModalProps) => {
|
|||||||
>
|
>
|
||||||
{status === 'loading' ? (
|
{status === 'loading' ? (
|
||||||
<>
|
<>
|
||||||
<Loader2 size={16} className="animate-spin" />
|
<Icon icon="ph:spinner-gap" width={16} className="animate-spin" />
|
||||||
Enviando...
|
Enviando...
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Send size={15} />
|
<Icon icon="ph:paper-plane-tilt" width={15} />
|
||||||
Enviar mensaje
|
Enviar mensaje
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
+8
-11
@@ -1,8 +1,8 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
|
|
||||||
export const CookieBanner = ({ isNavyBg }: ThemeProps) => {
|
export const CookieBanner = (_props: ThemeProps) => {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -19,34 +19,31 @@ export const CookieBanner = ({ isNavyBg }: ThemeProps) => {
|
|||||||
|
|
||||||
if (!visible) return null;
|
if (!visible) return null;
|
||||||
|
|
||||||
const bg = isNavyBg ? 'rgba(0,16,64,0.97)' : 'rgba(10,10,10,0.97)';
|
|
||||||
const border = isNavyBg ? 'rgba(255,255,255,0.1)' : 'rgba(255,255,255,0.08)';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
role="dialog"
|
role="dialog"
|
||||||
aria-label="Aviso de cookies"
|
aria-label="Aviso de cookies"
|
||||||
className="fixed bottom-6 left-1/2 z-50 w-[calc(100%-3rem)] max-w-xl -translate-x-1/2 px-6 py-4 shadow-2xl"
|
className="fixed bottom-6 left-1/2 z-50 w-[calc(100%-3rem)] max-w-xl -translate-x-1/2 px-6 py-4 shadow-2xl"
|
||||||
style={{
|
style={{
|
||||||
background: bg,
|
background: 'color-mix(in srgb, var(--card) 97%, transparent)',
|
||||||
border: `1px solid ${border}`,
|
border: '1px solid var(--border)',
|
||||||
borderRadius: 6,
|
borderRadius: 16,
|
||||||
backdropFilter: 'blur(16px)',
|
backdropFilter: 'blur(16px)',
|
||||||
WebkitBackdropFilter: 'blur(16px)',
|
WebkitBackdropFilter: 'blur(16px)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<p className="text-sm leading-relaxed" style={{ color: 'rgba(255,255,255,0.6)', maxWidth: '42ch' }}>
|
<p className="text-sm leading-relaxed" style={{ color: 'var(--muted-foreground)', maxWidth: '42ch' }}>
|
||||||
Usamos cookies para mejorar tu experiencia en el sitio.
|
Usamos cookies para mejorar tu experiencia en el sitio.
|
||||||
Al continuar, aceptas su uso.{' '}
|
Al continuar, aceptas su uso.{' '}
|
||||||
<a href="/privacidad" className="underline transition hover:text-white" style={{ color: 'rgba(255,255,255,0.45)' }}>
|
<a href="/privacidad" className="underline transition hover:opacity-80" style={{ color: 'var(--foreground)' }}>
|
||||||
Política de privacidad
|
Política de privacidad
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
onClick={accept}
|
onClick={accept}
|
||||||
className="shrink-0 px-5 py-2 text-sm font-bold text-white transition hover:opacity-90"
|
className="shrink-0 px-5 py-2 text-sm font-bold text-white transition hover:opacity-90"
|
||||||
style={{ background: '#3b82f6', borderRadius: 3, border: 'none', cursor: 'pointer' }}
|
style={{ background: '#3b82f6', borderRadius: 999, border: 'none', cursor: 'pointer' }}
|
||||||
>
|
>
|
||||||
Aceptar
|
Aceptar
|
||||||
</button>
|
</button>
|
||||||
+8
-8
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { ArrowUp } from 'lucide-react';
|
import { Icon } from '@iconify/react';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
import { type Dispatch, type SetStateAction, useState, useEffect } from 'react';
|
import { type Dispatch, type SetStateAction, useState, useEffect } from 'react';
|
||||||
|
|
||||||
const WHATSAPP_NUMBER = '529984814889';
|
const WHATSAPP_NUMBER = '529984814889';
|
||||||
@@ -11,12 +11,12 @@ interface FloatingButtonsProps extends ThemeProps {
|
|||||||
setIsNavyBg: Dispatch<SetStateAction<boolean>>;
|
setIsNavyBg: Dispatch<SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FloatingButtons = ({ isNavyBg, setIsNavyBg: _setIsNavyBg }: FloatingButtonsProps) => {
|
export const FloatingButtons = ({ setIsNavyBg: _setIsNavyBg }: FloatingButtonsProps) => {
|
||||||
const [showTop, setShowTop] = useState(false);
|
const [showTop, setShowTop] = useState(false);
|
||||||
const [showBubble, setShowBubble] = useState(false);
|
const [showBubble, setShowBubble] = useState(false);
|
||||||
const toggleBg = isNavyBg ? 'rgba(0,31,91,0.95)' : 'rgba(255,255,255,0.95)';
|
const toggleBg = 'color-mix(in srgb, var(--card) 85%, transparent)';
|
||||||
const toggleBorder = isNavyBg ? 'rgba(255,255,255,0.15)' : 'rgba(0,0,0,0.12)';
|
const toggleBorder = 'var(--border)';
|
||||||
const toggleColor = isNavyBg ? '#fbbf24' : '#001f5b';
|
const toggleColor = '#3b82f6';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onScroll = () => setShowTop(window.scrollY > 400);
|
const onScroll = () => setShowTop(window.scrollY > 400);
|
||||||
@@ -32,7 +32,7 @@ export const FloatingButtons = ({ isNavyBg, setIsNavyBg: _setIsNavyBg }: Floatin
|
|||||||
<button
|
<button
|
||||||
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
|
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
|
||||||
aria-label="Volver arriba"
|
aria-label="Volver arriba"
|
||||||
className="fixed bottom-6 left-6 z-50 flex h-12 w-12 items-center justify-center rounded-full shadow-lg transition-transform hover:scale-110 active:scale-95"
|
className="fixed bottom-24 left-6 z-50 flex h-12 w-12 items-center justify-center rounded-full shadow-lg transition-transform hover:scale-110 active:scale-95"
|
||||||
style={{
|
style={{
|
||||||
background: toggleBg,
|
background: toggleBg,
|
||||||
border: `1px solid ${toggleBorder}`,
|
border: `1px solid ${toggleBorder}`,
|
||||||
@@ -41,7 +41,7 @@ export const FloatingButtons = ({ isNavyBg, setIsNavyBg: _setIsNavyBg }: Floatin
|
|||||||
color: toggleColor,
|
color: toggleColor,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ArrowUp size={16} />
|
<Icon icon="ph:arrow-up" width={16} />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -1,42 +1,66 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { Mail, MapPin, MessageCircle } from "lucide-react";
|
import { Icon } from "@iconify/react";
|
||||||
import { FaFacebookF, FaLinkedinIn, FaMapMarkerAlt } from "react-icons/fa";
|
import { FaFacebookF, FaLinkedinIn, FaMapMarkerAlt } from "react-icons/fa";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import type { ThemeProps } from "@/app/types/ui";
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
import { pageLinks } from '@/app/home/data/navigationData';
|
import { pageLinks } from "@/app/(landing)/home/data/navigationData";
|
||||||
import { FaRegMessage } from "react-icons/fa6";
|
import { FaRegMessage } from "react-icons/fa6";
|
||||||
import { MdEmail } from "react-icons/md";
|
import { MdEmail } from "react-icons/md";
|
||||||
|
|
||||||
export const Footer = ({ isNavyBg }: ThemeProps) => {
|
export const Footer = ({ isNavyBg }: ThemeProps) => {
|
||||||
const bg = isNavyBg ? "#001040" : "#0a0a0a";
|
const bg = isNavyBg ? "var(--background)" : "#f9f9f7";
|
||||||
const sub = "rgba(255,255,255,0.45)";
|
const text = isNavyBg ? "#ffffff" : "#0a0a0a";
|
||||||
const border = "rgba(255,255,255,0.08)";
|
const sub = isNavyBg ? "rgba(255,255,255,0.45)" : "rgba(0,0,0,0.5)";
|
||||||
|
const faint = isNavyBg ? "rgba(255,255,255,0.25)" : "rgba(0,0,0,0.35)";
|
||||||
|
const border = isNavyBg ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.08)";
|
||||||
|
const cardBg = isNavyBg ? "color-mix(in srgb, var(--card) 72%, transparent)" : "color-mix(in srgb, #ffffff 72%, transparent)";
|
||||||
|
const chipBg = isNavyBg ? "rgba(255,255,255,0.07)" : "rgba(0,0,0,0.05)";
|
||||||
|
const chipBgHv = isNavyBg ? "rgba(255,255,255,0.14)" : "rgba(0,0,0,0.1)";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer
|
<footer
|
||||||
style={{ background: bg, borderTop: `1px solid ${border}` }}
|
style={{ background: bg, color: text }}
|
||||||
className="px-14 pt-10 transition-colors duration-500"
|
className="relative overflow-hidden px-4 py-12 transition-colors duration-500 sm:px-6 sm:py-16"
|
||||||
role="contentinfo"
|
role="contentinfo"
|
||||||
>
|
>
|
||||||
<div className="mx-auto max-w-7xl">
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute inset-0 bg-dot-grid text-border opacity-40"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute -bottom-24 -left-32 h-[24rem] w-[24rem] rounded-full blur-[110px]"
|
||||||
|
style={{ background: "rgba(59,130,246,0.12)" }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="relative mx-auto max-w-7xl rounded-[32px] px-8 pt-14 pb-2 sm:px-14 sm:pt-16"
|
||||||
|
style={{
|
||||||
|
background: cardBg,
|
||||||
|
border: `1px solid ${border}`,
|
||||||
|
backdropFilter: "blur(18px)",
|
||||||
|
WebkitBackdropFilter: "blur(18px)",
|
||||||
|
boxShadow: isNavyBg ? "0 20px 60px rgba(0,0,0,0.3)" : "0 20px 60px rgba(0,0,0,0.06)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
{/* Main grid */}
|
{/* Main grid */}
|
||||||
<div className="grid gap-14 md:grid-cols-[1.8fr_1fr_1.2fr]">
|
<div className="grid gap-16 md:grid-cols-[1.8fr_1fr_1.2fr]">
|
||||||
{/* Brand */}
|
{/* Brand */}
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-6 flex items-center gap-2.5">
|
<div className="mb-6 flex items-center gap-2.5">
|
||||||
<img
|
<img
|
||||||
src="/icons/Logo_blanco.svg"
|
src={isNavyBg ? "/icons/Logo_blanco.svg" : "/icons/Logo_negro.svg"}
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
className="h-11 w-11 shrink-0 object-contain"
|
className="h-12 w-12 shrink-0 object-contain"
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col leading-none">
|
<div className="flex flex-col leading-none">
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "'Quicksand', sans-serif",
|
fontFamily: "'Quicksand', sans-serif",
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
fontSize: 19,
|
fontSize: 21,
|
||||||
letterSpacing: "-0.01em",
|
letterSpacing: "-0.01em",
|
||||||
color: "#ffffff",
|
color: text,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Rynext
|
Rynext
|
||||||
@@ -45,9 +69,9 @@ export const Footer = ({ isNavyBg }: ThemeProps) => {
|
|||||||
style={{
|
style={{
|
||||||
fontFamily: "'Quicksand', sans-serif",
|
fontFamily: "'Quicksand', sans-serif",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontSize: 12,
|
fontSize: 13,
|
||||||
letterSpacing: "0.04em",
|
letterSpacing: "0.04em",
|
||||||
color: "rgba(255,255,255,0.45)",
|
color: sub,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Technologies
|
Technologies
|
||||||
@@ -55,27 +79,27 @@ export const Footer = ({ isNavyBg }: ThemeProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
className="text-sm leading-relaxed mb-8"
|
className="text-base leading-relaxed mb-8"
|
||||||
style={{ color: sub, maxWidth: "30ch" }}
|
style={{ color: sub, maxWidth: "32ch" }}
|
||||||
>
|
>
|
||||||
Diseñamos y construimos sistemas empresariales a medida,
|
Diseñamos y construimos sistemas empresariales a medida,
|
||||||
arquitectura real, sin atajos técnicos.
|
arquitectura real, sin atajos técnicos.
|
||||||
</p>
|
</p>
|
||||||
{/* Social */}
|
{/* Social */}
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-2.5">
|
||||||
<a
|
<a
|
||||||
href="https://www.facebook.com/RynextTechnologies/"
|
href="https://www.facebook.com/RynextTechnologies/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
aria-label="Rynext en Facebook"
|
aria-label="Rynext en Facebook"
|
||||||
className="flex h-9 w-9 items-center justify-center rounded transition-colors"
|
className="flex h-11 w-11 items-center justify-center rounded-full transition-colors"
|
||||||
style={{ background: "rgba(255,255,255,0.07)", color: sub }}
|
style={{ background: chipBg, color: sub }}
|
||||||
onMouseEnter={(e) => {
|
onMouseEnter={(e) => {
|
||||||
e.currentTarget.style.background = "rgba(255,255,255,0.14)";
|
e.currentTarget.style.background = chipBgHv;
|
||||||
e.currentTarget.style.color = "#fff";
|
e.currentTarget.style.color = text;
|
||||||
}}
|
}}
|
||||||
onMouseLeave={(e) => {
|
onMouseLeave={(e) => {
|
||||||
e.currentTarget.style.background = "rgba(255,255,255,0.07)";
|
e.currentTarget.style.background = chipBg;
|
||||||
e.currentTarget.style.color = sub;
|
e.currentTarget.style.color = sub;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -87,14 +111,14 @@ export const Footer = ({ isNavyBg }: ThemeProps) => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
aria-label="Rynext en LinkedIn"
|
aria-label="Rynext en LinkedIn"
|
||||||
className="flex h-9 w-9 items-center justify-center rounded transition-colors"
|
className="flex h-11 w-11 items-center justify-center rounded-full transition-colors"
|
||||||
style={{ background: "rgba(255,255,255,0.07)", color: sub }}
|
style={{ background: chipBg, color: sub }}
|
||||||
onMouseEnter={(e) => {
|
onMouseEnter={(e) => {
|
||||||
e.currentTarget.style.background = "rgba(255,255,255,0.14)";
|
e.currentTarget.style.background = chipBgHv;
|
||||||
e.currentTarget.style.color = "#fff";
|
e.currentTarget.style.color = text;
|
||||||
}}
|
}}
|
||||||
onMouseLeave={(e) => {
|
onMouseLeave={(e) => {
|
||||||
e.currentTarget.style.background = "rgba(255,255,255,0.07)";
|
e.currentTarget.style.background = chipBg;
|
||||||
e.currentTarget.style.color = sub;
|
e.currentTarget.style.color = sub;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -105,14 +129,14 @@ export const Footer = ({ isNavyBg }: ThemeProps) => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
aria-label="Rynext en WhatsApp"
|
aria-label="Rynext en WhatsApp"
|
||||||
className="flex h-9 w-9 items-center justify-center rounded transition-colors"
|
className="flex h-11 w-11 items-center justify-center rounded-full transition-colors"
|
||||||
style={{ background: "rgba(255,255,255,0.07)", color: sub }}
|
style={{ background: chipBg, color: sub }}
|
||||||
onMouseEnter={(e) => {
|
onMouseEnter={(e) => {
|
||||||
e.currentTarget.style.background = "rgba(255,255,255,0.14)";
|
e.currentTarget.style.background = chipBgHv;
|
||||||
e.currentTarget.style.color = "#fff";
|
e.currentTarget.style.color = text;
|
||||||
}}
|
}}
|
||||||
onMouseLeave={(e) => {
|
onMouseLeave={(e) => {
|
||||||
e.currentTarget.style.background = "rgba(255,255,255,0.07)";
|
e.currentTarget.style.background = chipBg;
|
||||||
e.currentTarget.style.color = sub;
|
e.currentTarget.style.color = sub;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -126,7 +150,7 @@ export const Footer = ({ isNavyBg }: ThemeProps) => {
|
|||||||
<p
|
<p
|
||||||
className="text-mono-label mb-6"
|
className="text-mono-label mb-6"
|
||||||
style={{
|
style={{
|
||||||
color: "rgba(255,255,255,0.25)",
|
color: faint,
|
||||||
letterSpacing: "0.12em",
|
letterSpacing: "0.12em",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -139,7 +163,7 @@ export const Footer = ({ isNavyBg }: ThemeProps) => {
|
|||||||
href={link.href}
|
href={link.href}
|
||||||
className="text-sm font-medium transition-colors"
|
className="text-sm font-medium transition-colors"
|
||||||
style={{ color: sub, textDecoration: "none" }}
|
style={{ color: sub, textDecoration: "none" }}
|
||||||
onMouseEnter={(e) => (e.currentTarget.style.color = "#fff")}
|
onMouseEnter={(e) => (e.currentTarget.style.color = text)}
|
||||||
onMouseLeave={(e) => (e.currentTarget.style.color = sub)}
|
onMouseLeave={(e) => (e.currentTarget.style.color = sub)}
|
||||||
>
|
>
|
||||||
{link.label}
|
{link.label}
|
||||||
@@ -154,7 +178,7 @@ export const Footer = ({ isNavyBg }: ThemeProps) => {
|
|||||||
<p
|
<p
|
||||||
className="text-mono-label mb-6"
|
className="text-mono-label mb-6"
|
||||||
style={{
|
style={{
|
||||||
color: "rgba(255,255,255,0.25)",
|
color: faint,
|
||||||
letterSpacing: "0.12em",
|
letterSpacing: "0.12em",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -162,18 +186,18 @@ export const Footer = ({ isNavyBg }: ThemeProps) => {
|
|||||||
</p>
|
</p>
|
||||||
<ul className="flex flex-col gap-4">
|
<ul className="flex flex-col gap-4">
|
||||||
<li className="flex items-center gap-3">
|
<li className="flex items-center gap-3">
|
||||||
<FaMapMarkerAlt className="text-white text-center" />
|
<FaMapMarkerAlt className="text-center" style={{ color: text }} />
|
||||||
<span className="text-sm leading-snug" style={{ color: sub }}>
|
<span className="text-sm leading-snug" style={{ color: sub }}>
|
||||||
Cancún, Quintana Roo. México
|
Cancún, Quintana Roo. México
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-center gap-3">
|
<li className="flex items-center gap-3">
|
||||||
<MdEmail className="text-white text-center" />
|
<MdEmail className="text-center" style={{ color: text }} />
|
||||||
<a
|
<a
|
||||||
href="mailto:[email protected]"
|
href="mailto:[email protected]"
|
||||||
className="text-sm font-medium transition-colors"
|
className="text-sm font-medium transition-colors"
|
||||||
style={{ color: sub }}
|
style={{ color: sub }}
|
||||||
onMouseEnter={(e) => (e.currentTarget.style.color = "#fff")}
|
onMouseEnter={(e) => (e.currentTarget.style.color = text)}
|
||||||
onMouseLeave={(e) => (e.currentTarget.style.color = sub)}
|
onMouseLeave={(e) => (e.currentTarget.style.color = sub)}
|
||||||
>
|
>
|
||||||
contacto@rynext.com.mx
|
contacto@rynext.com.mx
|
||||||
@@ -182,40 +206,41 @@ export const Footer = ({ isNavyBg }: ThemeProps) => {
|
|||||||
<li className="mt-2">
|
<li className="mt-2">
|
||||||
<a
|
<a
|
||||||
href="mailto:[email protected]"
|
href="mailto:[email protected]"
|
||||||
className="inline-flex items-center gap-2 px-5 py-2.5 text-sm font-bold text-white transition hover:opacity-90"
|
className="group inline-flex items-center gap-2 px-6 py-3 text-base font-bold text-white transition hover:scale-[1.03] active:scale-[0.98]"
|
||||||
style={{ background: "#3b82f6", borderRadius: 3 }}
|
style={{ background: "#3b82f6", borderRadius: 999 }}
|
||||||
>
|
>
|
||||||
Hablemos de tu proyecto
|
Hablemos de tu proyecto
|
||||||
|
<Icon icon="ph:arrow-up-right" width={14} className="transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5" />
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Bottom bar — full width */}
|
{/* Bottom bar */}
|
||||||
<div
|
<div className="mt-10 border-t" style={{ borderColor: border }}>
|
||||||
className="mt-10 -mx-8 px-8 md:-mx-14 md:px-14"
|
<div className="flex flex-col items-center gap-2 py-5 sm:flex-row sm:justify-between">
|
||||||
style={{ borderTop: `1px solid ${border}` }}
|
<p className="text-xs" style={{ color: faint }}>
|
||||||
>
|
<Link
|
||||||
<div className="mx-auto flex max-w-7xl flex-col items-center gap-2 py-5 sm:flex-row sm:justify-between">
|
href="/admin/login"
|
||||||
<p className="text-xs" style={{ color: "rgba(255,255,255,0.25)" }}>
|
aria-label="Acceso interno"
|
||||||
© {new Date().getFullYear()} Rynext Technologies — Todos los
|
style={{ color: "inherit", textDecoration: "none" }}
|
||||||
derechos reservados.
|
>
|
||||||
</p>
|
©
|
||||||
<Link
|
</Link>{" "}
|
||||||
href="/privacidad"
|
{new Date().getFullYear()} Rynext Technologies — Todos los
|
||||||
className="text-xs transition-colors"
|
derechos reservados.
|
||||||
style={{ color: "rgba(255,255,255,0.25)", textDecoration: "none" }}
|
</p>
|
||||||
onMouseEnter={(e) =>
|
<Link
|
||||||
(e.currentTarget.style.color = "rgba(255,255,255,0.6)")
|
href="/privacidad"
|
||||||
}
|
className="text-xs transition-colors"
|
||||||
onMouseLeave={(e) =>
|
style={{ color: faint, textDecoration: "none" }}
|
||||||
(e.currentTarget.style.color = "rgba(255,255,255,0.25)")
|
onMouseEnter={(e) => (e.currentTarget.style.color = sub)}
|
||||||
}
|
onMouseLeave={(e) => (e.currentTarget.style.color = faint)}
|
||||||
>
|
>
|
||||||
Aviso de Privacidad
|
Aviso de Privacidad
|
||||||
</Link>
|
</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from "@/app/components/Loader";
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
"use client";
|
||||||
|
import { Icon } from "@iconify/react";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
const TRACK_SRC = "/audio/musica.mp3";
|
||||||
|
const PREF_KEY = "rynext_music_enabled";
|
||||||
|
|
||||||
|
export const MusicPlayer = ({
|
||||||
|
className = "bottom-6 left-6",
|
||||||
|
inline = false,
|
||||||
|
}: {
|
||||||
|
className?: string;
|
||||||
|
inline?: boolean;
|
||||||
|
}) => {
|
||||||
|
const audioRef = useRef<HTMLAudioElement>(null);
|
||||||
|
const [playing, setPlaying] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const audio = audioRef.current;
|
||||||
|
if (!audio) return;
|
||||||
|
|
||||||
|
audio.volume = 0.05;
|
||||||
|
|
||||||
|
// Respeta la última preferencia del usuario (guardada en localStorage):
|
||||||
|
// si la silenció, no la reinicia sola al recargar la página.
|
||||||
|
let muted = false;
|
||||||
|
try {
|
||||||
|
muted = localStorage.getItem(PREF_KEY) === "off";
|
||||||
|
} catch {}
|
||||||
|
if (muted) return;
|
||||||
|
|
||||||
|
// Si el navegador bloquea el autoplay, no la arrancamos con cualquier
|
||||||
|
// interacción (scroll, tecla, etc.) — solo el botón de reproducir debe
|
||||||
|
// encenderla, para que no "se mueva sola" al navegar la página.
|
||||||
|
audio.play().then(() => setPlaying(true)).catch(() => {});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
const audio = audioRef.current;
|
||||||
|
if (!audio) return;
|
||||||
|
if (playing) {
|
||||||
|
audio.pause();
|
||||||
|
setPlaying(false);
|
||||||
|
try { localStorage.setItem(PREF_KEY, "off"); } catch {}
|
||||||
|
} else {
|
||||||
|
audio
|
||||||
|
.play()
|
||||||
|
.then(() => {
|
||||||
|
setPlaying(true);
|
||||||
|
try { localStorage.setItem(PREF_KEY, "on"); } catch {}
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<audio ref={audioRef} src={TRACK_SRC} loop preload="auto" />
|
||||||
|
{inline ? (
|
||||||
|
<button
|
||||||
|
onClick={toggle}
|
||||||
|
aria-label={playing ? "Silenciar música" : "Reproducir música"}
|
||||||
|
aria-pressed={playing}
|
||||||
|
className="flex items-center justify-center w-8 h-8 rounded-lg text-muted-foreground hover:bg-muted hover:text-foreground transition-colors shrink-0"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon={playing ? "ph:speaker-high-fill" : "ph:speaker-slash-fill"}
|
||||||
|
width={16}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
onClick={toggle}
|
||||||
|
aria-label={playing ? "Silenciar música" : "Reproducir música"}
|
||||||
|
aria-pressed={playing}
|
||||||
|
className={`fixed ${className} z-50 flex h-12 w-12 items-center justify-center rounded-full shadow-lg transition-transform hover:scale-110 active:scale-95`}
|
||||||
|
style={{
|
||||||
|
background: "color-mix(in srgb, var(--card) 85%, transparent)",
|
||||||
|
border: "1px solid var(--border)",
|
||||||
|
backdropFilter: "blur(8px)",
|
||||||
|
cursor: "pointer",
|
||||||
|
color: "#3b82f6",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon={playing ? "ph:speaker-high-fill" : "ph:speaker-slash-fill"}
|
||||||
|
width={18}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
'use client';
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
import { pageLinks } from '@/app/(landing)/home/data/navigationData';
|
||||||
|
import { useAuthStore } from '@/app/admin/store/authStore';
|
||||||
|
import ThemeToggle from './ui/hero-01-utils/theme-toggle';
|
||||||
|
|
||||||
|
export const Navbar = () => {
|
||||||
|
const [scrolled, setScrolled] = useState(false);
|
||||||
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
|
const [hovered, setHovered] = useState<string | null>(null);
|
||||||
|
const [mounted, setMounted] = useState(false);
|
||||||
|
const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
|
||||||
|
const rawPathname = usePathname();
|
||||||
|
const pathname = rawPathname?.replace(/\/$/, '') || '/';
|
||||||
|
const links = pageLinks.filter(l => l.href !== '/privacidad');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const scrollToContact = () => {
|
||||||
|
setMenuOpen(false);
|
||||||
|
const el = document.getElementById('contacto');
|
||||||
|
if (el) el.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
else window.location.href = '/#contacto';
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const onScroll = () => setScrolled(window.scrollY > 40);
|
||||||
|
window.addEventListener('scroll', onScroll, { passive: true });
|
||||||
|
return () => window.removeEventListener('scroll', onScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMenuOpen(false);
|
||||||
|
}, [pathname]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<motion.header
|
||||||
|
className="fixed inset-x-0 top-0 z-50 flex justify-center px-4 pt-4 sm:px-6"
|
||||||
|
initial={{ y: -40, opacity: 0 }}
|
||||||
|
animate={{ y: 0, opacity: 1 }}
|
||||||
|
transition={{ duration: 0.65, ease: [0.22, 1, 0.36, 1] }}
|
||||||
|
role="banner"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="flex w-full max-w-7xl items-center justify-between gap-4 rounded-full px-4 py-2.5 transition-shadow duration-300"
|
||||||
|
style={{
|
||||||
|
background: 'color-mix(in srgb, var(--card) 72%, transparent)',
|
||||||
|
border: '1px solid var(--border)',
|
||||||
|
backdropFilter: 'blur(18px)',
|
||||||
|
WebkitBackdropFilter: 'blur(18px)',
|
||||||
|
boxShadow: scrolled
|
||||||
|
? '0 8px 30px rgba(0,0,0,0.12)'
|
||||||
|
: '0 1px 2px rgba(0,0,0,0.03)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Logo */}
|
||||||
|
<Link href="/" aria-label="Rynext Technologies — inicio" className="flex shrink-0 items-center gap-2">
|
||||||
|
<img src="/icons/Logo_negro.svg" alt="Logo" className="h-8 w-8 shrink-0 object-contain dark:hidden" />
|
||||||
|
<img src="/icons/Logo_blanco.svg" alt="Logo" className="hidden h-8 w-8 shrink-0 object-contain dark:block" />
|
||||||
|
<span className="flex flex-col leading-none">
|
||||||
|
<span
|
||||||
|
style={{ fontFamily: "'Quicksand', sans-serif", fontWeight: 700, fontSize: 16, letterSpacing: '-0.01em', color: 'var(--foreground)' }}
|
||||||
|
>
|
||||||
|
Rynext
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
style={{ fontFamily: "'Quicksand', sans-serif", fontWeight: 500, fontSize: 10, letterSpacing: '0.04em', color: 'var(--muted-foreground)' }}
|
||||||
|
>
|
||||||
|
Technologies
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Desktop nav — pill with sliding highlight */}
|
||||||
|
<nav
|
||||||
|
className="relative hidden items-center gap-0.5 rounded-full p-1 md:flex"
|
||||||
|
style={{ background: 'var(--muted)' }}
|
||||||
|
aria-label="Navegación principal"
|
||||||
|
onMouseLeave={() => setHovered(null)}
|
||||||
|
>
|
||||||
|
{links.map((link) => {
|
||||||
|
const active = pathname === link.href;
|
||||||
|
const isHovered = hovered === link.href;
|
||||||
|
// Solo un link muestra la píldora a la vez: el hovered tiene prioridad
|
||||||
|
// sobre el activo, para que nunca existan dos motion.span con el mismo
|
||||||
|
// layoutId montados al mismo tiempo (eso causaba el lag al pasar el mouse).
|
||||||
|
const showPill = hovered ? isHovered : active;
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={link.href}
|
||||||
|
href={link.href}
|
||||||
|
onMouseEnter={() => setHovered(link.href)}
|
||||||
|
className="relative z-10 rounded-full px-3.5 py-1.5 text-sm font-semibold no-underline transition-colors"
|
||||||
|
style={{ color: active || isHovered ? 'var(--foreground)' : 'var(--muted-foreground)' }}
|
||||||
|
>
|
||||||
|
{showPill && (
|
||||||
|
<motion.span
|
||||||
|
layoutId="nav-pill"
|
||||||
|
className="absolute inset-0 -z-10 rounded-full"
|
||||||
|
style={{ background: 'var(--background)', boxShadow: '0 1px 2px rgba(0,0,0,0.06)' }}
|
||||||
|
transition={{ type: 'spring', stiffness: 400, damping: 32 }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{link.label}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{/* Right cluster */}
|
||||||
|
<div className="flex shrink-0 items-center gap-2">
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<ThemeToggle />
|
||||||
|
</div>
|
||||||
|
{mounted && isAuthenticated && (
|
||||||
|
<Link
|
||||||
|
href="/admin/dashboard"
|
||||||
|
className="hidden items-center gap-1.5 rounded-full px-4 py-2 text-sm font-bold no-underline transition hover:scale-[1.03] active:scale-[0.98] sm:inline-flex"
|
||||||
|
style={{ color: 'var(--foreground)', background: 'var(--muted)', border: '1px solid var(--border)' }}
|
||||||
|
>
|
||||||
|
<Icon icon="ph:squares-four" width={14} />
|
||||||
|
Dashboard
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={scrollToContact}
|
||||||
|
className="group hidden items-center gap-1.5 rounded-full px-4 py-2 text-sm font-bold text-white transition hover:scale-[1.03] active:scale-[0.98] sm:inline-flex"
|
||||||
|
style={{ background: '#3b82f6', border: 'none', cursor: 'pointer' }}
|
||||||
|
>
|
||||||
|
Hablemos
|
||||||
|
<Icon icon="ph:arrow-up-right" width={14} className="transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Mobile toggle */}
|
||||||
|
<div className="flex items-center gap-1 md:hidden">
|
||||||
|
<ThemeToggle />
|
||||||
|
<button
|
||||||
|
onClick={() => setMenuOpen((v) => !v)}
|
||||||
|
className="flex h-9 w-9 items-center justify-center rounded-full"
|
||||||
|
style={{ color: 'var(--foreground)', background: 'var(--muted)', border: 'none', cursor: 'pointer' }}
|
||||||
|
aria-label={menuOpen ? 'Cerrar menú' : 'Abrir menú'}
|
||||||
|
aria-expanded={menuOpen}
|
||||||
|
>
|
||||||
|
{menuOpen ? <Icon icon="ph:x" width={18} /> : <Icon icon="ph:list" width={18} />}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.header>
|
||||||
|
|
||||||
|
{/* Mobile menu — floating card */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{menuOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: -12, scale: 0.97 }}
|
||||||
|
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||||
|
exit={{ opacity: 0, y: -12, scale: 0.97 }}
|
||||||
|
transition={{ duration: 0.2, ease: [0.22, 1, 0.36, 1] }}
|
||||||
|
className="fixed inset-x-4 top-[76px] z-40 rounded-3xl p-5 md:hidden"
|
||||||
|
style={{
|
||||||
|
background: 'color-mix(in srgb, var(--card) 96%, transparent)',
|
||||||
|
border: '1px solid var(--border)',
|
||||||
|
backdropFilter: 'blur(18px)',
|
||||||
|
WebkitBackdropFilter: 'blur(18px)',
|
||||||
|
boxShadow: '0 16px 40px rgba(0,0,0,0.18)',
|
||||||
|
}}
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
aria-label="Menú de navegación"
|
||||||
|
>
|
||||||
|
<nav className="flex flex-col gap-1">
|
||||||
|
{pageLinks.map((link) => {
|
||||||
|
const active = pathname === link.href;
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={link.href}
|
||||||
|
href={link.href}
|
||||||
|
className="rounded-xl px-3 py-2.5 text-base font-semibold no-underline"
|
||||||
|
style={{
|
||||||
|
color: active ? 'var(--foreground)' : 'var(--muted-foreground)',
|
||||||
|
background: active ? 'var(--muted)' : 'transparent',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{link.label}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</nav>
|
||||||
|
<div className="mt-4 flex flex-col gap-2">
|
||||||
|
{mounted && isAuthenticated && (
|
||||||
|
<Link
|
||||||
|
href="/admin/dashboard"
|
||||||
|
className="flex w-full items-center justify-center gap-1.5 rounded-full py-3 text-sm font-bold no-underline"
|
||||||
|
style={{ color: 'var(--foreground)', background: 'var(--muted)', border: '1px solid var(--border)' }}
|
||||||
|
>
|
||||||
|
<Icon icon="ph:squares-four" width={14} />
|
||||||
|
Dashboard
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={scrollToContact}
|
||||||
|
className="flex w-full items-center justify-center gap-1.5 rounded-full py-3 text-sm font-bold text-white"
|
||||||
|
style={{ background: '#3b82f6', border: 'none', cursor: 'pointer' }}
|
||||||
|
>
|
||||||
|
Hablemos
|
||||||
|
<Icon icon="ph:arrow-up-right" width={14} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,56 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { Slot } from "@radix-ui/react-slot"
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/app/(landing)/lib/utils"
|
||||||
|
|
||||||
|
const buttonVariants = cva(
|
||||||
|
"inline-flex items-center justify-center whitespace-nowrap rounded-full text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||||
|
destructive:
|
||||||
|
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||||
|
outline:
|
||||||
|
"border border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground",
|
||||||
|
secondary:
|
||||||
|
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||||
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: "h-10 px-4 py-2",
|
||||||
|
sm: "h-9 rounded-full px-3",
|
||||||
|
lg: "h-11 rounded-full px-8",
|
||||||
|
icon: "h-10 w-10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
export interface ButtonProps
|
||||||
|
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
|
VariantProps<typeof buttonVariants> {
|
||||||
|
asChild?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||||
|
const Comp = asChild ? Slot : "button"
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Button.displayName = "Button"
|
||||||
|
|
||||||
|
export { Button, buttonVariants }
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/app/(landing)/lib/utils"
|
||||||
|
|
||||||
|
function Empty({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="empty"
|
||||||
|
className={cn(
|
||||||
|
"flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="empty-header"
|
||||||
|
className={cn(
|
||||||
|
"flex max-w-sm flex-col items-center gap-2 text-center",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyMediaVariants = cva(
|
||||||
|
"flex shrink-0 items-center justify-center mb-2 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-transparent",
|
||||||
|
icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function EmptyMedia({
|
||||||
|
className,
|
||||||
|
variant = "default",
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"div"> & VariantProps<typeof emptyMediaVariants>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="empty-icon"
|
||||||
|
data-variant={variant}
|
||||||
|
className={cn(emptyMediaVariants({ variant, className }))}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="empty-title"
|
||||||
|
className={cn("text-lg font-medium tracking-tight", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="empty-description"
|
||||||
|
className={cn(
|
||||||
|
"text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function EmptyContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="empty-content"
|
||||||
|
className={cn(
|
||||||
|
"flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Empty,
|
||||||
|
EmptyHeader,
|
||||||
|
EmptyTitle,
|
||||||
|
EmptyDescription,
|
||||||
|
EmptyContent,
|
||||||
|
EmptyMedia,
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { motion } from "framer-motion"
|
||||||
|
import { useCompanies } from "@/app/(landing)/home/services/companies"
|
||||||
|
import { assetUrl } from "@/app/(landing)/services/api"
|
||||||
|
|
||||||
|
export default function BrandSlider() {
|
||||||
|
const { data } = useCompanies()
|
||||||
|
const companies = (data ?? []).filter((c) => c.showInLanding && c.logoUrl)
|
||||||
|
|
||||||
|
if (companies.length === 0) return null
|
||||||
|
|
||||||
|
// Con pocas marcas reales, un número inflado ("+1000") se nota falso —
|
||||||
|
// mostramos un mensaje honesto en ese caso y solo presumimos la cifra
|
||||||
|
// cuando el catálogo ya tiene un volumen que la respalde.
|
||||||
|
const trustLabel =
|
||||||
|
companies.length >= 10
|
||||||
|
? `Con la confianza de +${Math.floor(companies.length / 10) * 10} marcas grandes y pequeñas`
|
||||||
|
: "Empresas que ya confían en nosotros"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
className="relative z-10 w-full pt-16"
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, amount: 0.4 }}
|
||||||
|
transition={{ duration: 0.7, ease: [0.22, 1, 0.36, 1] }}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-4 sm:gap-6">
|
||||||
|
<span className="h-px flex-1 bg-gradient-to-r from-transparent to-border" />
|
||||||
|
<p className="shrink-0 text-xs text-muted-foreground sm:text-sm">
|
||||||
|
{trustLabel}
|
||||||
|
</p>
|
||||||
|
<span className="h-px flex-1 bg-gradient-to-l from-transparent to-border" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-8 flex flex-wrap items-center justify-center gap-x-10 gap-y-6">
|
||||||
|
{companies.map((brand) => (
|
||||||
|
<div
|
||||||
|
key={brand.id}
|
||||||
|
title={brand.name}
|
||||||
|
className="flex items-center opacity-80 transition hover:opacity-100"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={assetUrl(brand.logoUrl)}
|
||||||
|
alt={brand.name}
|
||||||
|
className="h-[150px] w-auto max-w-[150px] object-contain"
|
||||||
|
onError={(e) => {
|
||||||
|
(e.currentTarget.closest("[title]") as HTMLElement | null)?.style.setProperty("display", "none")
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import {
|
||||||
|
motion,
|
||||||
|
MotionConfig,
|
||||||
|
type Variants,
|
||||||
|
} from "framer-motion"
|
||||||
|
import { Icon } from "@iconify/react"
|
||||||
|
|
||||||
|
import { Button } from "@/app/(landing)/components/ui/button"
|
||||||
|
import BrandSlider from "./brand-slider"
|
||||||
|
|
||||||
|
export interface AvatarList {
|
||||||
|
image: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HeroSectionProps {
|
||||||
|
avatarList?: AvatarList[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const container: Variants = {
|
||||||
|
hidden: {},
|
||||||
|
show: {
|
||||||
|
transition: {
|
||||||
|
staggerChildren: 0.1,
|
||||||
|
delayChildren: 0.15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const item: Variants = {
|
||||||
|
hidden: { opacity: 0, y: 22, filter: "blur(4px)" },
|
||||||
|
show: {
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
filter: "blur(0px)",
|
||||||
|
transition: { type: "spring", stiffness: 300, damping: 28, mass: 0.9 },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const wordContainer: Variants = {
|
||||||
|
hidden: {},
|
||||||
|
show: {
|
||||||
|
transition: { staggerChildren: 0.055, delayChildren: 0.3 },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const word: Variants = {
|
||||||
|
hidden: { opacity: 0, y: 16, filter: "blur(6px)" },
|
||||||
|
show: {
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
filter: "blur(0px)",
|
||||||
|
transition: { type: "spring", stiffness: 260, damping: 24 },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const HEADLINE_LINE_1 = ["Construimos", "experiencias", "que"]
|
||||||
|
const HEADLINE_LINE_2 = ["impulsan", "tu", "negocio"]
|
||||||
|
|
||||||
|
export default function HeroSection({}: HeroSectionProps) {
|
||||||
|
return (
|
||||||
|
<MotionConfig reducedMotion="user">
|
||||||
|
<section
|
||||||
|
className="relative isolate flex min-h-dvh flex-col justify-center px-4 pb-20 pt-32 sm:px-6 sm:pb-28 sm:pt-40 lg:px-8"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="animate-hero-blob-a pointer-events-none absolute -bottom-24 -left-32 -z-20 h-[24rem] w-[24rem] rounded-full bg-accent/[0.12] blur-[110px]"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="animate-hero-blob-b pointer-events-none absolute -top-24 -right-32 -z-20 h-[24rem] w-[24rem] rounded-full bg-[#8b5cf6]/[0.12] blur-[110px]"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="mx-auto flex max-w-4xl flex-col items-start text-left"
|
||||||
|
>
|
||||||
|
<motion.div variants={container} initial="hidden" animate="show">
|
||||||
|
<motion.span
|
||||||
|
variants={item}
|
||||||
|
className="inline-flex items-center gap-1.5 rounded-full border border-accent/20 bg-accent/10 px-3 py-1 text-xs font-semibold text-accent"
|
||||||
|
>
|
||||||
|
<Icon icon="ph:sparkle" className="h-3.5 w-3.5" />
|
||||||
|
Diseño & desarrollo digital
|
||||||
|
</motion.span>
|
||||||
|
|
||||||
|
<motion.h1
|
||||||
|
variants={wordContainer}
|
||||||
|
className="text-display mt-6 max-w-2xl text-foreground"
|
||||||
|
>
|
||||||
|
<span className="block">
|
||||||
|
{HEADLINE_LINE_1.map((w, i) => (
|
||||||
|
<motion.span key={i} variants={word} className="inline-block">
|
||||||
|
{w}
|
||||||
|
{i < HEADLINE_LINE_1.length - 1 ? " " : ""}
|
||||||
|
</motion.span>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
<span className="block text-accent">
|
||||||
|
{HEADLINE_LINE_2.map((w, i) => (
|
||||||
|
<motion.span key={i} variants={word} className="inline-block">
|
||||||
|
{w}
|
||||||
|
{i < HEADLINE_LINE_2.length - 1 ? " " : ""}
|
||||||
|
</motion.span>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
</motion.h1>
|
||||||
|
|
||||||
|
<motion.p
|
||||||
|
variants={item}
|
||||||
|
className="mt-6 max-w-xl text-balance text-base text-muted-foreground sm:text-lg"
|
||||||
|
>
|
||||||
|
Diseño, desarrollo y estrategia digital para marcas que quieren
|
||||||
|
crecer. De la idea al producto en producción.
|
||||||
|
</motion.p>
|
||||||
|
|
||||||
|
<motion.div variants={item} className="mt-8 flex flex-col gap-3 sm:flex-row">
|
||||||
|
<motion.div whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.97 }}>
|
||||||
|
<Button
|
||||||
|
size="lg"
|
||||||
|
className="group shadow-lg shadow-blue-500/20 transition-colors hover:bg-[#2563eb]"
|
||||||
|
>
|
||||||
|
Empezar un proyecto
|
||||||
|
<Icon icon="ph:arrow-right" className="ml-2 h-4 w-4 transition-transform duration-300 group-hover:translate-x-1" />
|
||||||
|
</Button>
|
||||||
|
</motion.div>
|
||||||
|
<motion.div whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.97 }}>
|
||||||
|
<Button
|
||||||
|
size="lg"
|
||||||
|
variant="outline"
|
||||||
|
className="border-primary/15 text-primary hover:border-primary hover:bg-transparent hover:text-primary"
|
||||||
|
>
|
||||||
|
Ver portafolio
|
||||||
|
</Button>
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<BrandSlider />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</MotionConfig>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import { Icon } from "@iconify/react"
|
||||||
|
|
||||||
|
import { Button } from "@/app/(landing)/components/ui/button"
|
||||||
|
|
||||||
|
export default function ThemeToggle() {
|
||||||
|
const [isDark, setIsDark] = React.useState(false)
|
||||||
|
const [mounted, setMounted] = React.useState(false)
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setMounted(true)
|
||||||
|
const stored = localStorage.getItem("theme")
|
||||||
|
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
|
const dark = stored ? stored === "dark" : prefersDark
|
||||||
|
setIsDark(dark)
|
||||||
|
document.documentElement.classList.toggle("dark", dark)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const toggle = () => {
|
||||||
|
const next = !isDark
|
||||||
|
setIsDark(next)
|
||||||
|
document.documentElement.classList.toggle("dark", next)
|
||||||
|
localStorage.setItem("theme", next ? "dark" : "light")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mounted) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
aria-label="Cambiar tema"
|
||||||
|
disabled
|
||||||
|
className="text-foreground hover:bg-foreground/10"
|
||||||
|
>
|
||||||
|
<Icon icon="ph:sun" className="h-5 w-5" />
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
onClick={toggle}
|
||||||
|
aria-label="Cambiar tema"
|
||||||
|
className="text-foreground hover:bg-foreground/10"
|
||||||
|
>
|
||||||
|
{isDark ? <Icon icon="ph:sun" className="h-5 w-5" /> : <Icon icon="ph:moon" className="h-5 w-5" />}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/app/(landing)/lib/utils"
|
||||||
|
|
||||||
|
export interface InputProps
|
||||||
|
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||||
|
|
||||||
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
|
({ className, type, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type={type}
|
||||||
|
className={cn(
|
||||||
|
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Input.displayName = "Input"
|
||||||
|
|
||||||
|
export { Input }
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/app/(landing)/lib/utils"
|
||||||
|
|
||||||
|
const labelVariants = cva(
|
||||||
|
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||||
|
)
|
||||||
|
|
||||||
|
const Label = React.forwardRef<
|
||||||
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||||
|
VariantProps<typeof labelVariants>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<LabelPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn(labelVariants(), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
Label.displayName = LabelPrimitive.Root.displayName
|
||||||
|
|
||||||
|
export { Label }
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { ChevronDownIcon } from "@radix-ui/react-icons"
|
||||||
|
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
|
||||||
|
import { cva } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/app/(landing)/lib/utils"
|
||||||
|
|
||||||
|
const NavigationMenu = React.forwardRef<
|
||||||
|
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<NavigationMenuPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative z-10 flex max-w-max flex-1 items-center justify-center",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<NavigationMenuViewport />
|
||||||
|
</NavigationMenuPrimitive.Root>
|
||||||
|
))
|
||||||
|
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
|
||||||
|
|
||||||
|
const NavigationMenuList = React.forwardRef<
|
||||||
|
React.ElementRef<typeof NavigationMenuPrimitive.List>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<NavigationMenuPrimitive.List
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"group flex flex-1 list-none items-center justify-center space-x-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
|
||||||
|
|
||||||
|
const NavigationMenuItem = NavigationMenuPrimitive.Item
|
||||||
|
|
||||||
|
const navigationMenuTriggerStyle = cva(
|
||||||
|
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"
|
||||||
|
)
|
||||||
|
|
||||||
|
const NavigationMenuTrigger = React.forwardRef<
|
||||||
|
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<NavigationMenuPrimitive.Trigger
|
||||||
|
ref={ref}
|
||||||
|
className={cn(navigationMenuTriggerStyle(), "group", className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}{" "}
|
||||||
|
<ChevronDownIcon
|
||||||
|
className="relative top-[1px] ml-1 h-3 w-3 transition duration-300 group-data-[state=open]:rotate-180"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</NavigationMenuPrimitive.Trigger>
|
||||||
|
))
|
||||||
|
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
|
||||||
|
|
||||||
|
const NavigationMenuContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<NavigationMenuPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName
|
||||||
|
|
||||||
|
const NavigationMenuLink = NavigationMenuPrimitive.Link
|
||||||
|
|
||||||
|
const NavigationMenuViewport = React.forwardRef<
|
||||||
|
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<div className={cn("absolute left-0 top-full flex justify-center")}>
|
||||||
|
<NavigationMenuPrimitive.Viewport
|
||||||
|
className={cn(
|
||||||
|
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
NavigationMenuViewport.displayName =
|
||||||
|
NavigationMenuPrimitive.Viewport.displayName
|
||||||
|
|
||||||
|
const NavigationMenuIndicator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<NavigationMenuPrimitive.Indicator
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
|
||||||
|
</NavigationMenuPrimitive.Indicator>
|
||||||
|
))
|
||||||
|
NavigationMenuIndicator.displayName =
|
||||||
|
NavigationMenuPrimitive.Indicator.displayName
|
||||||
|
|
||||||
|
export {
|
||||||
|
navigationMenuTriggerStyle,
|
||||||
|
NavigationMenu,
|
||||||
|
NavigationMenuList,
|
||||||
|
NavigationMenuItem,
|
||||||
|
NavigationMenuContent,
|
||||||
|
NavigationMenuTrigger,
|
||||||
|
NavigationMenuLink,
|
||||||
|
NavigationMenuIndicator,
|
||||||
|
NavigationMenuViewport,
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { createContext, useContext, useState } from 'react';
|
import { createContext, useContext, useState } from 'react';
|
||||||
import { ContactModal } from '@/app/components/ContactModal';
|
import { ContactModal } from '@/app/(landing)/components/ContactModal';
|
||||||
|
import { useIsDark } from '@/app/(landing)/hooks/useIsDark';
|
||||||
|
|
||||||
interface ContactCtx {
|
interface ContactCtx {
|
||||||
open: () => void;
|
open: () => void;
|
||||||
@@ -10,10 +11,11 @@ const ContactContext = createContext<ContactCtx>({ open: () => {} });
|
|||||||
|
|
||||||
export const ContactProvider = ({ children }: { children: React.ReactNode }) => {
|
export const ContactProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const isDark = useIsDark();
|
||||||
return (
|
return (
|
||||||
<ContactContext.Provider value={{ open: () => setIsOpen(true) }}>
|
<ContactContext.Provider value={{ open: () => setIsOpen(true) }}>
|
||||||
{children}
|
{children}
|
||||||
<ContactModal isOpen={isOpen} onClose={() => setIsOpen(false)} isNavyBg={false} />
|
<ContactModal isOpen={isOpen} onClose={() => setIsOpen(false)} isNavyBg={isDark} />
|
||||||
</ContactContext.Provider>
|
</ContactContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
"use client";
|
||||||
|
import { useIsDark } from "@/app/(landing)/hooks/useIsDark";
|
||||||
|
import HeroSection from "@/app/(landing)/components/ui/hero-01-utils/hero";
|
||||||
|
import type { AvatarList } from "@/app/(landing)/components/ui/hero-01-utils/hero";
|
||||||
|
import { Problem } from "@/app/(landing)/home/sections/Problem";
|
||||||
|
import { Machinery } from "@/app/(landing)/home/sections/Machinery";
|
||||||
|
import { Services } from "@/app/(landing)/home/sections/Services";
|
||||||
|
import { FAQ } from "@/app/(landing)/home/sections/FAQ";
|
||||||
|
import { Partners } from "@/app/(landing)/home/sections/Partners";
|
||||||
|
import { ContactSection } from "@/app/(landing)/home/sections/ContactSection";
|
||||||
|
|
||||||
|
const avatarList: AvatarList[] = [
|
||||||
|
{
|
||||||
|
image:
|
||||||
|
"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=128&h=128&fit=crop&crop=faces",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image:
|
||||||
|
"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=128&h=128&fit=crop&crop=faces",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image:
|
||||||
|
"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=128&h=128&fit=crop&crop=faces",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image:
|
||||||
|
"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=128&h=128&fit=crop&crop=faces",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function HomePage() {
|
||||||
|
const isDark = useIsDark();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main id="main-content" className="relative">
|
||||||
|
<HeroSection avatarList={avatarList} />
|
||||||
|
<Problem isNavyBg={isDark} />
|
||||||
|
<Machinery isNavyBg={isDark} />
|
||||||
|
<Services isNavyBg={isDark} />
|
||||||
|
<FAQ isNavyBg={isDark} />
|
||||||
|
<Partners isNavyBg={isDark} />
|
||||||
|
<ContactSection isNavyBg={isDark} />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,22 @@
|
|||||||
|
export const faqs = [
|
||||||
|
{
|
||||||
|
q: '¿Cuánto tiempo tarda un proyecto típico?',
|
||||||
|
a: 'Un sistema funcional suele estar en producción entre 8 y 16 semanas, trabajando en sprints cortos con entregables medibles.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: '¿Trabajan con empresas fuera de Cancún o de México?',
|
||||||
|
a: 'Sí, trabajamos de forma remota con empresas en todo México y en otros países.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: '¿Qué pasa con el mantenimiento y soporte después de la entrega?',
|
||||||
|
a: 'Se entrega documentado y en producción, con acompañamiento post-lanzamiento según el acuerdo de cada proyecto.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: '¿Pueden integrarse con el ERP o los sistemas que ya tenemos?',
|
||||||
|
a: 'Sí, la integración con SAP, Odoo, sistemas legacy y APIs internas es parte de nuestro núcleo de trabajo.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: '¿Cómo es el primer paso para arrancar un proyecto?',
|
||||||
|
a: 'Agendamos una sesión técnica sin costo para analizar tu operación y presentar una ruta concreta de construcción.',
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
export const machineryData = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
num: '01',
|
||||||
|
title: 'OPERACIONES',
|
||||||
|
description: 'Plataformas internas y control de procesos críticos, sin fricción.',
|
||||||
|
tags: ['Portales de gestión', 'Automatización de flujos', 'Reportes operacionales', 'Control de acceso por rol'],
|
||||||
|
icon: "ph:squares-four",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
num: '02',
|
||||||
|
title: 'VENTAS',
|
||||||
|
description: 'Del contacto con el cliente al comprobante fiscal, todo integrado.',
|
||||||
|
tags: ['E-commerce a medida', 'Integración de pagos', 'Facturación y CFDI', 'Recuperación de carritos'],
|
||||||
|
icon: "ph:shopping-cart",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
num: '03',
|
||||||
|
title: 'INTEGRACIONES',
|
||||||
|
description: 'Conectamos sistemas heterogéneos en un ecosistema coherente.',
|
||||||
|
tags: ['ERP / SAP / Odoo', 'APIs de terceros', 'Sincronización bidireccional', 'Webhooks y eventos'],
|
||||||
|
icon: "ph:flow-arrow",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
num: '04',
|
||||||
|
title: 'AUTOMATIZACIÓN',
|
||||||
|
description: 'Tareas repetitivas corriendo solas, para que tu equipo se enfoque en lo que sí requiere criterio humano.',
|
||||||
|
tags: ['Bots y pipelines', 'Procesamiento de datos', 'Notificaciones inteligentes', 'Triggers y colas'],
|
||||||
|
icon: "ph:lightning",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
num: '05',
|
||||||
|
title: 'DATOS',
|
||||||
|
description: 'Decisiones con evidencia: dashboards, modelos y alertas a tiempo.',
|
||||||
|
tags: ['Dashboards ejecutivos', 'Pipelines de datos', 'KPIs e instrumentación', 'Alertas y umbrales'],
|
||||||
|
icon: "ph:chart-bar",
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
export const pageLinks = [
|
export const pageLinks = [
|
||||||
{ label: 'Sobre Nosotros', href: '/sobre-nosotros' },
|
{ label: 'Inicio', href: '/' },
|
||||||
{ label: 'Productos', href: '/productos' },
|
{ label: 'Nosotros', href: '/sobre-nosotros' },
|
||||||
{ label: 'Portafolio', href: '/portafolio' },
|
{ label: 'Portafolio', href: '/portafolio' },
|
||||||
{ label: 'Blog', href: '/blog' },
|
{ label: 'Blog', href: '/blog' },
|
||||||
{ label: 'Aviso de Privacidad', href: '/privacidad' },
|
{ label: 'Aviso de Privacidad', href: '/privacidad' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const navLinks = [
|
export const navLinks = [
|
||||||
{ label: 'Soluciones', href: '#showcase' },
|
|
||||||
{ label: 'Portafolio', href: '#portafolio' },
|
{ label: 'Portafolio', href: '#portafolio' },
|
||||||
{ label: 'Sistemas', href: '#machinery' },
|
{ label: 'Sistemas', href: '#machinery' },
|
||||||
{ label: 'Proceso', href: '#proceso' },
|
{ label: 'Proceso', href: '#proceso' },
|
||||||
+3
-5
@@ -1,5 +1,3 @@
|
|||||||
import { Building2, Layers3, ShieldCheck } from 'lucide-react';
|
|
||||||
|
|
||||||
export const comparisonRows = [
|
export const comparisonRows = [
|
||||||
{
|
{
|
||||||
criterion: 'Adaptación al negocio',
|
criterion: 'Adaptación al negocio',
|
||||||
@@ -27,16 +25,16 @@ export const proofCards = [
|
|||||||
{
|
{
|
||||||
title: 'Diseño de experiencia',
|
title: 'Diseño de experiencia',
|
||||||
description: 'UX orientada a adopción, claridad y flujo de trabajo real.',
|
description: 'UX orientada a adopción, claridad y flujo de trabajo real.',
|
||||||
icon: Layers3,
|
icon: "ph:stack-simple",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Arquitectura robusta',
|
title: 'Arquitectura robusta',
|
||||||
description: 'Infraestructura, seguridad y escalabilidad definida desde el inicio.',
|
description: 'Infraestructura, seguridad y escalabilidad definida desde el inicio.',
|
||||||
icon: ShieldCheck,
|
icon: "ph:shield-check",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Equipo senior',
|
title: 'Equipo senior',
|
||||||
description: 'Product owner, ingeniería y operación trabajando con criterio empresarial.',
|
description: 'Product owner, ingeniería y operación trabajando con criterio empresarial.',
|
||||||
icon: Building2,
|
icon: "ph:buildings",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
File renamed without changes.
File renamed without changes.
@@ -1,5 +1,4 @@
|
|||||||
import { Code, Cloud, ShieldCheck, TrendingUp } from 'lucide-react';
|
import type { ServiceItem } from '@/app/(landing)/types/ui';
|
||||||
import type { ServiceItem } from '@/app/types/ui';
|
|
||||||
|
|
||||||
export const servicesData: ServiceItem[] = [
|
export const servicesData: ServiceItem[] = [
|
||||||
{
|
{
|
||||||
@@ -7,7 +6,7 @@ export const servicesData: ServiceItem[] = [
|
|||||||
title: 'Desarrollo de software',
|
title: 'Desarrollo de software',
|
||||||
description: 'Plataformas web y APIs construidas con arquitectura limpia, código mantenible y enfoque en rendimiento real.',
|
description: 'Plataformas web y APIs construidas con arquitectura limpia, código mantenible y enfoque en rendimiento real.',
|
||||||
features: ['APIs REST & GraphQL', 'Microservicios y monolitos modulares', 'Code review y auditorías técnicas'],
|
features: ['APIs REST & GraphQL', 'Microservicios y monolitos modulares', 'Code review y auditorías técnicas'],
|
||||||
icon: Code,
|
icon: "ph:code",
|
||||||
gridCols: 'md:col-span-7',
|
gridCols: 'md:col-span-7',
|
||||||
accent: 'blue',
|
accent: 'blue',
|
||||||
},
|
},
|
||||||
@@ -16,7 +15,7 @@ export const servicesData: ServiceItem[] = [
|
|||||||
title: 'Infraestructura en la nube',
|
title: 'Infraestructura en la nube',
|
||||||
description: 'Diseño, migración y operación de infraestructura cloud escalable con alta disponibilidad.',
|
description: 'Diseño, migración y operación de infraestructura cloud escalable con alta disponibilidad.',
|
||||||
features: ['AWS, GCP y Azure', 'CI/CD y DevOps', 'Monitoreo y alertas 24/7'],
|
features: ['AWS, GCP y Azure', 'CI/CD y DevOps', 'Monitoreo y alertas 24/7'],
|
||||||
icon: Cloud,
|
icon: "ph:cloud",
|
||||||
gridCols: 'md:col-span-5',
|
gridCols: 'md:col-span-5',
|
||||||
accent: 'blue',
|
accent: 'blue',
|
||||||
},
|
},
|
||||||
@@ -25,7 +24,7 @@ export const servicesData: ServiceItem[] = [
|
|||||||
title: 'Ciberseguridad aplicada',
|
title: 'Ciberseguridad aplicada',
|
||||||
description: 'Protección de datos, auditorías de seguridad y protocolos que cumplen estándares empresariales.',
|
description: 'Protección de datos, auditorías de seguridad y protocolos que cumplen estándares empresariales.',
|
||||||
features: ['Pruebas de penetración', 'Cifrado end-to-end', 'Cumplimiento GDPR / ISO'],
|
features: ['Pruebas de penetración', 'Cifrado end-to-end', 'Cumplimiento GDPR / ISO'],
|
||||||
icon: ShieldCheck,
|
icon: "ph:shield-check",
|
||||||
gridCols: 'md:col-span-5',
|
gridCols: 'md:col-span-5',
|
||||||
accent: 'red',
|
accent: 'red',
|
||||||
},
|
},
|
||||||
@@ -34,7 +33,7 @@ export const servicesData: ServiceItem[] = [
|
|||||||
title: 'Producto y crecimiento',
|
title: 'Producto y crecimiento',
|
||||||
description: 'Estrategia tecnológica alineada al negocio para lanzar, medir y escalar con datos reales.',
|
description: 'Estrategia tecnológica alineada al negocio para lanzar, medir y escalar con datos reales.',
|
||||||
features: ['Roadmap técnico y de producto', 'Analytics e instrumentación', 'Optimización de conversión'],
|
features: ['Roadmap técnico y de producto', 'Analytics e instrumentación', 'Optimización de conversión'],
|
||||||
icon: TrendingUp,
|
icon: "ph:trend-up",
|
||||||
gridCols: 'md:col-span-7',
|
gridCols: 'md:col-span-7',
|
||||||
accent: 'red',
|
accent: 'red',
|
||||||
},
|
},
|
||||||
-6
@@ -5,9 +5,3 @@ export const valores = [
|
|||||||
{ num: '04', titulo: 'Iteración con propósito', desc: 'Construimos en ciclos cortos y medibles. Cada entrega aporta valor real y permite ajustar la dirección.' },
|
{ num: '04', titulo: 'Iteración con propósito', desc: 'Construimos en ciclos cortos y medibles. Cada entrega aporta valor real y permite ajustar la dirección.' },
|
||||||
{ num: '05', titulo: 'Responsabilidad completa', desc: 'Desde el análisis hasta la producción, somos dueños del resultado. No transferimos riesgo al cliente.' },
|
{ num: '05', titulo: 'Responsabilidad completa', desc: 'Desde el análisis hasta la producción, somos dueños del resultado. No transferimos riesgo al cliente.' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const porQueRynext = [
|
|
||||||
{ num: '01', titulo: 'Diseño desde la raíz', desc: 'Cada sistema empieza con un análisis profundo de la operación. No adaptamos plantillas, diseñamos desde cero para el contexto específico del negocio.' },
|
|
||||||
{ num: '02', titulo: 'Equipo técnico propio', desc: 'Sin intermediarios. El equipo que analiza tu operación es el mismo que diseña la arquitectura y escribe el código.' },
|
|
||||||
{ num: '03', titulo: 'Enfoque en producción', desc: 'No entregamos prototipos. Entregamos sistemas listos para operar con carga real, datos reales y usuarios reales.' },
|
|
||||||
];
|
|
||||||
File renamed without changes.
@@ -1,11 +1,11 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
import { anatomyLayers as layers } from '@/app/home/data/anatomyData';
|
import { anatomyLayers as layers } from '@/app/(landing)/home/data/anatomyData';
|
||||||
|
|
||||||
export const Anatomy = ({ isNavyBg }: ThemeProps) => {
|
export const Anatomy = ({ isNavyBg }: ThemeProps) => {
|
||||||
const bg = isNavyBg ? '#0d1117' : '#f5f5f3';
|
const bg = isNavyBg ? 'var(--background)' : '#f5f5f3';
|
||||||
const text = isNavyBg ? '#eef0f4' : '#0a0a0a';
|
const text = isNavyBg ? 'var(--foreground)' : '#0a0a0a';
|
||||||
const sub = isNavyBg ? 'rgba(255,255,255,0.45)' : '#6a6866';
|
const sub = isNavyBg ? 'rgba(255,255,255,0.45)' : '#6a6866';
|
||||||
const border = isNavyBg ? 'rgba(255,255,255,0.08)' : '#dddbd5';
|
const border = isNavyBg ? 'rgba(255,255,255,0.08)' : '#dddbd5';
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ export const Anatomy = ({ isNavyBg }: ThemeProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Layers — always visible */}
|
{/* Layers — always visible */}
|
||||||
<div style={{ border: `1px solid ${border}`, borderRadius: 4, overflow: 'hidden' }}>
|
<div style={{ border: `1px solid ${border}`, borderRadius: 20, overflow: 'hidden' }}>
|
||||||
{layers.map((layer, i) => (
|
{layers.map((layer, i) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={layer.id}
|
key={layer.id}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import Loader from '@/app/components/Loader';
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
import { useCompanies } from "@/app/home/services/companies";
|
import { useCompanies } from '@/app/(landing)/home/services/companies';
|
||||||
import { assetUrl } from "@/app/services/api";
|
import { assetUrl } from '@/app/(landing)/services/api';
|
||||||
import type { ThemeProps } from "@/app/types/ui";
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
|
|
||||||
function ClientsInner({ isNavyBg }: ThemeProps) {
|
function ClientsInner({ isNavyBg }: ThemeProps) {
|
||||||
const { data, isLoading } = useCompanies();
|
const { data, isLoading } = useCompanies();
|
||||||
|
|
||||||
const bg = isNavyBg ? "#0a0f1e" : "#f0efec";
|
const bg = isNavyBg ? "var(--background)" : "#f0efec";
|
||||||
const border = isNavyBg ? "rgba(255,255,255,0.07)" : "rgba(0,0,0,0.07)";
|
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 label = isNavyBg ? "rgba(255,255,255,0.28)" : "rgba(0,0,0,0.28)";
|
||||||
|
|
||||||
@@ -58,12 +58,15 @@ function ClientsInner({ isNavyBg }: ThemeProps) {
|
|||||||
width: "auto",
|
width: "auto",
|
||||||
maxWidth: 200,
|
maxWidth: 200,
|
||||||
objectFit: "contain",
|
objectFit: "contain",
|
||||||
filter: isNavyBg
|
// grayscale solo: invert+brightness(0) aplanaba logos a color
|
||||||
? "brightness(0) invert(1) grayscale(1)"
|
// (fotos/JPEG) a un bloque negro o blanco ilegible en dark.
|
||||||
: "grayscale(1)",
|
filter: "grayscale(1)",
|
||||||
opacity: 0.55,
|
opacity: 0.55,
|
||||||
transition: "opacity 250ms",
|
transition: "opacity 250ms",
|
||||||
}}
|
}}
|
||||||
|
onError={(e) => {
|
||||||
|
(e.currentTarget as HTMLImageElement).style.display = "none";
|
||||||
|
}}
|
||||||
onMouseEnter={(e) =>
|
onMouseEnter={(e) =>
|
||||||
((e.currentTarget as HTMLImageElement).style.opacity = "1")
|
((e.currentTarget as HTMLImageElement).style.opacity = "1")
|
||||||
}
|
}
|
||||||
+20
-16
@@ -1,8 +1,8 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { Send, CheckCircle, AlertCircle, Loader2 } from 'lucide-react';
|
import { Icon } from '@iconify/react';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
|
|
||||||
const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'https://localhost:7001';
|
const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'https://localhost:7001';
|
||||||
|
|
||||||
@@ -13,13 +13,12 @@ export const ContactSection = ({ isNavyBg }: ThemeProps) => {
|
|||||||
const [form, setForm] = useState(initialForm);
|
const [form, setForm] = useState(initialForm);
|
||||||
const [status, setStatus] = useState<Status>('idle');
|
const [status, setStatus] = useState<Status>('idle');
|
||||||
|
|
||||||
const bg = isNavyBg ? '#080c14' : '#f5f5f3';
|
const text = isNavyBg ? 'var(--foreground)' : '#0a0a0a';
|
||||||
const text = isNavyBg ? '#ffffff' : '#0a0a0a';
|
|
||||||
const sub = isNavyBg ? 'rgba(255,255,255,0.45)' : '#6a6866';
|
const sub = isNavyBg ? 'rgba(255,255,255,0.45)' : '#6a6866';
|
||||||
const border = isNavyBg ? 'rgba(255,255,255,0.08)' : '#dddbd5';
|
const border = isNavyBg ? 'rgba(255,255,255,0.08)' : '#dddbd5';
|
||||||
const card = isNavyBg ? 'rgba(255,255,255,0.03)' : '#ffffff';
|
const card = isNavyBg ? 'rgba(255,255,255,0.03)' : '#ffffff';
|
||||||
const inputStyle: React.CSSProperties = {
|
const inputStyle: React.CSSProperties = {
|
||||||
width: '100%', borderRadius: 6, padding: '12px 14px',
|
width: '100%', borderRadius: 12, padding: '12px 14px',
|
||||||
fontSize: 14, fontFamily: 'inherit', outline: 'none',
|
fontSize: 14, fontFamily: 'inherit', outline: 'none',
|
||||||
transition: 'border-color 150ms',
|
transition: 'border-color 150ms',
|
||||||
...(isNavyBg
|
...(isNavyBg
|
||||||
@@ -60,10 +59,18 @@ export const ContactSection = ({ isNavyBg }: ThemeProps) => {
|
|||||||
<section
|
<section
|
||||||
id="contacto"
|
id="contacto"
|
||||||
aria-labelledby="contact-heading"
|
aria-labelledby="contact-heading"
|
||||||
style={{ background: bg, borderTop: `1px solid ${border}` }}
|
className="relative px-8 py-20 md:px-14 transition-colors duration-500"
|
||||||
className="px-8 py-28 md:px-14 transition-colors duration-500"
|
|
||||||
>
|
>
|
||||||
<div className="mx-auto max-w-7xl grid gap-16 lg:grid-cols-[1fr_1.2fr] lg:items-start">
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute inset-0 bg-dot-grid text-border opacity-40"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute -right-32 -top-24 h-[24rem] w-[24rem] rounded-full blur-[110px]"
|
||||||
|
style={{ background: 'rgba(139,92,246,0.12)' }}
|
||||||
|
/>
|
||||||
|
<div className="relative mx-auto max-w-7xl grid gap-16 lg:grid-cols-[1fr_1.2fr] lg:items-start">
|
||||||
|
|
||||||
{/* Left — copy */}
|
{/* Left — copy */}
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -72,9 +79,6 @@ export const ContactSection = ({ isNavyBg }: ThemeProps) => {
|
|||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
|
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
|
||||||
>
|
>
|
||||||
<span className="block text-xs font-semibold uppercase tracking-[0.14em] mb-4" style={{ color: '#3b82f6' }}>
|
|
||||||
Contacto
|
|
||||||
</span>
|
|
||||||
<h2 id="contact-heading" className="text-headline mb-6" style={{ color: text, maxWidth: '20ch' }}>
|
<h2 id="contact-heading" className="text-headline mb-6" style={{ color: text, maxWidth: '20ch' }}>
|
||||||
Hablemos de tu proyecto.
|
Hablemos de tu proyecto.
|
||||||
</h2>
|
</h2>
|
||||||
@@ -102,11 +106,11 @@ export const ContactSection = ({ isNavyBg }: ThemeProps) => {
|
|||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: true }}
|
||||||
transition={{ duration: 0.6, delay: 0.1, ease: [0.22, 1, 0.36, 1] }}
|
transition={{ duration: 0.6, delay: 0.1, ease: [0.22, 1, 0.36, 1] }}
|
||||||
style={{ background: card, border: `1px solid ${border}`, borderRadius: 8, padding: '40px 36px' }}
|
style={{ background: card, border: `1px solid ${border}`, borderRadius: 24, padding: '40px 36px' }}
|
||||||
>
|
>
|
||||||
{status === 'success' ? (
|
{status === 'success' ? (
|
||||||
<div className="flex flex-col items-center justify-center gap-4 py-10 text-center">
|
<div className="flex flex-col items-center justify-center gap-4 py-10 text-center">
|
||||||
<CheckCircle size={48} style={{ color: '#22c55e' }} />
|
<Icon icon="ph:check-circle" width={48} style={{ color: "#22c55e" }} />
|
||||||
<h3 className="font-display font-bold text-lg" style={{ color: text }}>¡Mensaje enviado!</h3>
|
<h3 className="font-display font-bold text-lg" style={{ color: text }}>¡Mensaje enviado!</h3>
|
||||||
<p className="text-sm leading-relaxed" style={{ color: sub, maxWidth: '32ch' }}>
|
<p className="text-sm leading-relaxed" style={{ color: sub, maxWidth: '32ch' }}>
|
||||||
Recibimos tu solicitud. Un miembro del equipo te contactará pronto.
|
Recibimos tu solicitud. Un miembro del equipo te contactará pronto.
|
||||||
@@ -156,7 +160,7 @@ export const ContactSection = ({ isNavyBg }: ThemeProps) => {
|
|||||||
|
|
||||||
{status === 'error' && (
|
{status === 'error' && (
|
||||||
<div className="flex items-center gap-2 px-4 py-3 rounded-lg" style={{ background: 'rgba(239,68,68,0.08)', border: '1px solid rgba(239,68,68,0.2)' }}>
|
<div className="flex items-center gap-2 px-4 py-3 rounded-lg" style={{ background: 'rgba(239,68,68,0.08)', border: '1px solid rgba(239,68,68,0.2)' }}>
|
||||||
<AlertCircle size={15} style={{ color: '#ef4444', flexShrink: 0 }} />
|
<Icon icon="ph:warning-circle" width={15} style={{ color: '#ef4444', flexShrink: 0 }} />
|
||||||
<p className="text-sm" style={{ color: '#ef4444' }}>
|
<p className="text-sm" style={{ color: '#ef4444' }}>
|
||||||
Hubo un error al enviar. Intenta de nuevo o escríbenos a contacto@rynext.com.mx
|
Hubo un error al enviar. Intenta de nuevo o escríbenos a contacto@rynext.com.mx
|
||||||
</p>
|
</p>
|
||||||
@@ -170,9 +174,9 @@ export const ContactSection = ({ isNavyBg }: ThemeProps) => {
|
|||||||
style={{ background: '#3b82f6', border: 'none', cursor: 'pointer' }}
|
style={{ background: '#3b82f6', border: 'none', cursor: 'pointer' }}
|
||||||
>
|
>
|
||||||
{status === 'loading' ? (
|
{status === 'loading' ? (
|
||||||
<><Loader2 size={16} className="animate-spin" />Enviando...</>
|
<><Icon icon="ph:spinner-gap" width={16} className="animate-spin" />Enviando...</>
|
||||||
) : (
|
) : (
|
||||||
<><Send size={15} />Enviar mensaje</>
|
<><Icon icon="ph:paper-plane-tilt" width={15} />Enviar mensaje</>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { ArrowRight } from "lucide-react";
|
import { Icon } from "@iconify/react";
|
||||||
import { Button } from '@/app/components/Button';
|
import { Button } from '@/app/(landing)/components/Button';
|
||||||
import type { ThemeProps } from "@/app/types/ui";
|
import type { ThemeProps } from "@/app/(landing)/types/ui";
|
||||||
|
|
||||||
export const CtaBanner = ({ isNavyBg }: ThemeProps) => {
|
export const CtaBanner = ({ isNavyBg }: ThemeProps) => {
|
||||||
const scrollToContact = () => {
|
const scrollToContact = () => {
|
||||||
const el = document.getElementById("contacto");
|
const el = document.getElementById("contacto");
|
||||||
if (el) el.scrollIntoView({ behavior: "smooth" });
|
if (el) el.scrollIntoView({ behavior: "smooth" });
|
||||||
};
|
};
|
||||||
const bg = isNavyBg ? "#001f5b" : "#f9f9f7";
|
const bg = isNavyBg ? "var(--background)" : "#f9f9f7";
|
||||||
const text = isNavyBg ? "#ffffff" : "#0a0a0a";
|
const text = isNavyBg ? "var(--foreground)" : "#0a0a0a";
|
||||||
const sub = isNavyBg ? "rgba(255,255,255,0.45)" : "rgba(0,0,0,0.45)";
|
const sub = isNavyBg ? "rgba(255,255,255,0.45)" : "rgba(0,0,0,0.45)";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -62,7 +62,7 @@ export const CtaBanner = ({ isNavyBg }: ThemeProps) => {
|
|||||||
isNavyBg ? "shadow-xl shadow-red-900/30" : "rounded-md"
|
isNavyBg ? "shadow-xl shadow-red-900/30" : "rounded-md"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Hablemos de tu proyecto <ArrowRight size={16} />
|
Hablemos de tu proyecto <Icon icon="ph:arrow-right" width={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { Plus } from 'lucide-react';
|
import { Icon } from '@iconify/react';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
import { faqs } from '@/app/home/data/faqData';
|
import { faqs } from '@/app/(landing)/home/data/faqData';
|
||||||
|
|
||||||
export const FAQ = ({ isNavyBg }: ThemeProps) => {
|
export const FAQ = ({ isNavyBg }: ThemeProps) => {
|
||||||
const [open, setOpen] = useState<number | null>(null);
|
const [open, setOpen] = useState<number | null>(null);
|
||||||
|
|
||||||
const bg = isNavyBg ? '#080c14' : '#f5f5f3';
|
const text = isNavyBg ? 'var(--foreground)' : '#0a0a0a';
|
||||||
const text = isNavyBg ? '#ffffff' : '#0a0a0a';
|
|
||||||
const sub = isNavyBg ? 'rgba(255,255,255,0.5)' : '#6a6866';
|
const sub = isNavyBg ? 'rgba(255,255,255,0.5)' : '#6a6866';
|
||||||
const border = isNavyBg ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.08)';
|
const border = isNavyBg ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.08)';
|
||||||
const rowBg = isNavyBg ? 'rgba(255,255,255,0.03)' : '#ffffff';
|
const rowBg = isNavyBg ? 'rgba(255,255,255,0.03)' : '#ffffff';
|
||||||
@@ -18,10 +17,14 @@ export const FAQ = ({ isNavyBg }: ThemeProps) => {
|
|||||||
<section
|
<section
|
||||||
id="faq"
|
id="faq"
|
||||||
aria-labelledby="faq-heading"
|
aria-labelledby="faq-heading"
|
||||||
style={{ background: bg, color: text, borderBottom: `1px solid ${border}` }}
|
style={{ color: text }}
|
||||||
className="px-8 py-28 md:px-14 transition-colors duration-500"
|
className="relative px-8 py-20 md:px-14 transition-colors duration-500"
|
||||||
>
|
>
|
||||||
<div className="mx-auto max-w-4xl">
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute inset-0 bg-dot-grid text-border opacity-40"
|
||||||
|
/>
|
||||||
|
<div className="relative mx-auto max-w-4xl">
|
||||||
<motion.div
|
<motion.div
|
||||||
className="mb-14"
|
className="mb-14"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
@@ -38,7 +41,7 @@ export const FAQ = ({ isNavyBg }: ThemeProps) => {
|
|||||||
</h2>
|
</h2>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
<div style={{ border: `1px solid ${border}`, borderRadius: 8, overflow: 'hidden' }}>
|
<div style={{ border: `1px solid ${border}`, borderRadius: 20, overflow: 'hidden' }}>
|
||||||
{faqs.map((faq, i) => {
|
{faqs.map((faq, i) => {
|
||||||
const isOpen = open === i;
|
const isOpen = open === i;
|
||||||
return (
|
return (
|
||||||
@@ -81,7 +84,7 @@ export const FAQ = ({ isNavyBg }: ThemeProps) => {
|
|||||||
marginTop: 2,
|
marginTop: 2,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Plus size={14} />
|
<Icon icon="ph:plus" width={14} />
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { ArrowRight } from 'lucide-react';
|
import { Icon } from '@iconify/react';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
import { Button } from '@/app/components/Button';
|
import { Button } from '@/app/(landing)/components/Button';
|
||||||
import { SystemMap } from './SystemMap';
|
import { SystemMap } from './SystemMap';
|
||||||
import { useContact } from '@/app/contexts/ContactContext';
|
import { useContact } from '@/app/(landing)/contexts/ContactContext';
|
||||||
|
|
||||||
const ease = [0.22, 1, 0.36, 1] as const;
|
const ease = [0.22, 1, 0.36, 1] as const;
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ export const Hero = ({ isNavyBg }: ThemeProps) => {
|
|||||||
className="flex flex-wrap items-center gap-6"
|
className="flex flex-wrap items-center gap-6"
|
||||||
>
|
>
|
||||||
<Button className="rounded-md" variant="primary" onClick={openContact}>
|
<Button className="rounded-md" variant="primary" onClick={openContact}>
|
||||||
Hablemos de tu proyecto <ArrowRight size={16} />
|
Hablemos de tu proyecto <Icon icon="ph:arrow-right" width={16} />
|
||||||
</Button>
|
</Button>
|
||||||
<button
|
<button
|
||||||
onClick={() => document.getElementById('machinery')?.scrollIntoView({ behavior: 'smooth' })}
|
onClick={() => document.getElementById('machinery')?.scrollIntoView({ behavior: 'smooth' })}
|
||||||
@@ -78,7 +78,7 @@ export const Hero = ({ isNavyBg }: ThemeProps) => {
|
|||||||
style={{ color: sub }}
|
style={{ color: sub }}
|
||||||
>
|
>
|
||||||
Explorar la maquinaria
|
Explorar la maquinaria
|
||||||
<ArrowRight size={14} className="transition-transform group-hover:translate-x-0.5" />
|
<Icon icon="ph:arrow-right" width={14} className="transition-transform group-hover:translate-x-0.5" />
|
||||||
</button>
|
</button>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
+41
-14
@@ -1,14 +1,14 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import { Icon } from '@iconify/react';
|
||||||
import { machineryData } from '@/app/home/data/machineryData';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
|
import { machineryData } from '@/app/(landing)/home/data/machineryData';
|
||||||
|
|
||||||
export const Machinery = ({ isNavyBg }: ThemeProps) => {
|
export const Machinery = ({ isNavyBg }: ThemeProps) => {
|
||||||
const [hovered, setHovered] = useState<number | null>(null);
|
const [hovered, setHovered] = useState<number | null>(null);
|
||||||
|
|
||||||
const bg = isNavyBg ? '#001f5b' : '#ffffff';
|
const text = isNavyBg ? 'var(--foreground)' : '#0a0a0a';
|
||||||
const text = isNavyBg ? '#ffffff' : '#0a0a0a';
|
|
||||||
const sub = isNavyBg ? 'rgba(255,255,255,0.45)' : '#6a6866';
|
const sub = isNavyBg ? 'rgba(255,255,255,0.45)' : '#6a6866';
|
||||||
const cardBg = isNavyBg ? 'rgba(255,255,255,0.06)' : '#fafaf9';
|
const cardBg = isNavyBg ? 'rgba(255,255,255,0.06)' : '#fafaf9';
|
||||||
const cardBdr = isNavyBg ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.09)';
|
const cardBdr = isNavyBg ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.09)';
|
||||||
@@ -18,11 +18,20 @@ export const Machinery = ({ isNavyBg }: ThemeProps) => {
|
|||||||
<section
|
<section
|
||||||
id="machinery"
|
id="machinery"
|
||||||
aria-labelledby="machinery-heading"
|
aria-labelledby="machinery-heading"
|
||||||
style={{ background: bg, color: text, borderBottom: `1px solid ${cardBdr}` }}
|
style={{ color: text }}
|
||||||
className="px-8 py-28 md:px-14 transition-colors duration-500"
|
className="relative px-8 py-20 md:px-14 transition-colors duration-500"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute inset-0 bg-dot-grid text-border opacity-40"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute -bottom-24 -left-32 h-[24rem] w-[24rem] rounded-full blur-[110px]"
|
||||||
|
style={{ background: 'rgba(59,130,246,0.12)' }}
|
||||||
|
/>
|
||||||
<motion.div
|
<motion.div
|
||||||
className="mx-auto max-w-7xl"
|
className="relative mx-auto max-w-7xl"
|
||||||
initial={{ opacity: 0, y: 28 }}
|
initial={{ opacity: 0, y: 28 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: false, amount: 0.1 }}
|
viewport={{ once: false, amount: 0.1 }}
|
||||||
@@ -30,7 +39,7 @@ export const Machinery = ({ isNavyBg }: ThemeProps) => {
|
|||||||
>
|
>
|
||||||
|
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="mb-16">
|
<div className="mb-10">
|
||||||
<h2
|
<h2
|
||||||
id="machinery-heading"
|
id="machinery-heading"
|
||||||
className="text-headline"
|
className="text-headline"
|
||||||
@@ -61,7 +70,7 @@ export const Machinery = ({ isNavyBg }: ThemeProps) => {
|
|||||||
? isNavyBg ? 'rgba(59,130,246,0.06)' : 'rgba(59,130,246,0.03)'
|
? isNavyBg ? 'rgba(59,130,246,0.06)' : 'rgba(59,130,246,0.03)'
|
||||||
: cardBg,
|
: cardBg,
|
||||||
border: `1px solid ${isHov ? 'rgba(59,130,246,0.25)' : cardBdr}`,
|
border: `1px solid ${isHov ? 'rgba(59,130,246,0.25)' : cardBdr}`,
|
||||||
borderRadius: 6,
|
borderRadius: 20,
|
||||||
padding: '28px 28px 32px',
|
padding: '28px 28px 32px',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
@@ -111,23 +120,23 @@ export const Machinery = ({ isNavyBg }: ThemeProps) => {
|
|||||||
|
|
||||||
{/* Icon */}
|
{/* Icon */}
|
||||||
<div style={{ position: 'relative', marginBottom: 20 }}>
|
<div style={{ position: 'relative', marginBottom: 20 }}>
|
||||||
{(() => { const Icon = item.icon; return Icon ? (
|
{item.icon ? (
|
||||||
<span style={{
|
<span style={{
|
||||||
display: 'inline-flex',
|
display: 'inline-flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
width: 44,
|
width: 44,
|
||||||
height: 44,
|
height: 44,
|
||||||
borderRadius: 10,
|
borderRadius: 12,
|
||||||
background: isHov
|
background: isHov
|
||||||
? 'rgba(59,130,246,0.15)'
|
? 'rgba(59,130,246,0.15)'
|
||||||
: isNavyBg ? 'rgba(255,255,255,0.07)' : 'rgba(59,130,246,0.07)',
|
: isNavyBg ? 'rgba(255,255,255,0.07)' : 'rgba(59,130,246,0.07)',
|
||||||
color: isHov ? '#3b82f6' : isNavyBg ? 'rgba(255,255,255,0.5)' : '#3b82f6',
|
color: isHov ? '#3b82f6' : isNavyBg ? 'rgba(255,255,255,0.5)' : '#3b82f6',
|
||||||
transition: 'background 220ms, color 220ms',
|
transition: 'background 220ms, color 220ms',
|
||||||
}}>
|
}}>
|
||||||
<Icon size={20} />
|
<Icon icon={item.icon} width={20} />
|
||||||
</span>
|
</span>
|
||||||
) : null; })()}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
@@ -144,11 +153,29 @@ export const Machinery = ({ isNavyBg }: ThemeProps) => {
|
|||||||
{item.title}
|
{item.title}
|
||||||
</h3>
|
</h3>
|
||||||
<p
|
<p
|
||||||
className="text-sm leading-relaxed"
|
className="text-sm leading-relaxed mb-4"
|
||||||
style={{ color: sub, transition: 'color 220ms' }}
|
style={{ color: sub, transition: 'color 220ms' }}
|
||||||
>
|
>
|
||||||
{item.description}
|
{item.description}
|
||||||
</p>
|
</p>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{item.tags.map((tag) => (
|
||||||
|
<span
|
||||||
|
key={tag}
|
||||||
|
style={{
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: 600,
|
||||||
|
padding: '3px 9px',
|
||||||
|
borderRadius: 99,
|
||||||
|
border: `1px solid ${cardBdr}`,
|
||||||
|
color: isNavyBg ? 'rgba(255,255,255,0.55)' : 'rgba(0,0,0,0.5)',
|
||||||
|
letterSpacing: '0.01em',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
"use client";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import { useTechPartners } from "@/app/(landing)/home/services/techPartners";
|
||||||
|
import { assetUrl } from "@/app/(landing)/services/api";
|
||||||
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
|
|
||||||
|
export const Partners = ({ isNavyBg }: ThemeProps) => {
|
||||||
|
const { data } = useTechPartners();
|
||||||
|
const label = isNavyBg ? "rgba(255,255,255,0.28)" : "rgba(0,0,0,0.28)";
|
||||||
|
const text = isNavyBg ? "var(--foreground)" : "#0a0a0a";
|
||||||
|
|
||||||
|
const partners = (data ?? [])
|
||||||
|
.filter((p) => p.isActive)
|
||||||
|
.sort((a, b) => a.displayOrder - b.displayOrder);
|
||||||
|
|
||||||
|
if (partners.length === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
aria-label="Partners tecnológicos de Rynext"
|
||||||
|
className="relative px-8 py-14 md:px-14 transition-colors duration-500"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute inset-0 bg-dot-grid text-border opacity-40"
|
||||||
|
/>
|
||||||
|
<motion.div
|
||||||
|
className="relative 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-x-10 gap-y-6">
|
||||||
|
{partners.map((p, i) => {
|
||||||
|
const content = p.logoUrl ? (
|
||||||
|
<img
|
||||||
|
src={assetUrl(p.logoUrl)}
|
||||||
|
alt={p.name}
|
||||||
|
className="h-[150px] w-auto max-w-[150px] object-contain"
|
||||||
|
onError={(e) => {
|
||||||
|
(e.currentTarget as HTMLImageElement).style.display = "none";
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span
|
||||||
|
className="text-lg font-bold tracking-tight"
|
||||||
|
style={{ color: text }}
|
||||||
|
>
|
||||||
|
{p.name}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
key={p.id}
|
||||||
|
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.05 }}
|
||||||
|
className="flex items-center opacity-70 transition hover:opacity-100"
|
||||||
|
>
|
||||||
|
{p.websiteUrl ? (
|
||||||
|
<a
|
||||||
|
href={p.websiteUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
title={p.name}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span title={p.name}>{content}</span>
|
||||||
|
)}
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
+19
-14
@@ -1,28 +1,33 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { X, Check } from 'lucide-react';
|
import { Icon } from '@iconify/react';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
import { comparisonRows, proofCards } from '@/app/home/data/platformAdvantageData';
|
import { comparisonRows, proofCards } from '@/app/(landing)/home/data/platformAdvantageData';
|
||||||
|
|
||||||
export const PlatformAdvantage = ({ isNavyBg }: ThemeProps) => {
|
export const PlatformAdvantage = ({ isNavyBg }: ThemeProps) => {
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
id="conveniencia"
|
id="conveniencia"
|
||||||
className={`section-wave px-6 py-28 md:px-12 transition-colors duration-500 ${
|
className={`section-wave relative overflow-hidden px-6 py-28 md:px-12 transition-colors duration-500 ${
|
||||||
isNavyBg ? 'bg-[#001749] text-white' : 'bg-slate-50 text-brand-black'
|
isNavyBg ? 'bg-[var(--background)] text-[var(--foreground)]' : 'bg-[#f9f9f7] text-brand-black'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="mx-auto max-w-7xl">
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute -right-32 bottom-0 h-[24rem] w-[24rem] rounded-full blur-[110px]"
|
||||||
|
style={{ background: 'rgba(59,130,246,0.10)' }}
|
||||||
|
/>
|
||||||
|
<div className="relative mx-auto max-w-7xl">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="mb-14 flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between">
|
<div className="mb-14 flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between">
|
||||||
<div className="max-w-3xl">
|
<div className="max-w-3xl">
|
||||||
<span className={`mb-3 block text-xs font-semibold uppercase tracking-[0.14em] ${
|
<span className={`mb-3 block text-xs font-semibold uppercase tracking-[0.14em] ${
|
||||||
isNavyBg ? 'text-sky-400' : 'text-brand-blue'
|
isNavyBg ? 'text-accent' : 'text-brand-blue'
|
||||||
}`}>
|
}`}>
|
||||||
Por qué Rynext
|
Por qué Rynext
|
||||||
</span>
|
</span>
|
||||||
<h2 className="text-section-title">
|
<h2 className="text-section-title">
|
||||||
Detrás de cada plataforma hay un equipo senior, una arquitectura clara y una ruta con sentido.
|
Rentar una licencia es fácil. Ser dueño de tu sistema, no.
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p className={`max-w-sm text-base leading-relaxed ${isNavyBg ? 'text-slate-400' : 'text-gray-500'}`}>
|
<p className={`max-w-sm text-base leading-relaxed ${isNavyBg ? 'text-slate-400' : 'text-gray-500'}`}>
|
||||||
@@ -45,7 +50,7 @@ export const PlatformAdvantage = ({ isNavyBg }: ThemeProps) => {
|
|||||||
Licencia SaaS
|
Licencia SaaS
|
||||||
</div>
|
</div>
|
||||||
<div className={`border-t px-6 py-4 font-bold md:border-t-0 md:border-l ${
|
<div className={`border-t px-6 py-4 font-bold md:border-t-0 md:border-l ${
|
||||||
isNavyBg ? 'border-white/8 text-sky-400' : 'border-gray-100 text-brand-blue'
|
isNavyBg ? 'border-white/8 text-accent' : 'border-gray-100 text-brand-blue'
|
||||||
}`}>
|
}`}>
|
||||||
Rynext software
|
Rynext software
|
||||||
</div>
|
</div>
|
||||||
@@ -67,13 +72,13 @@ export const PlatformAdvantage = ({ isNavyBg }: ThemeProps) => {
|
|||||||
<div className={`flex items-start gap-2.5 border-t px-6 py-5 md:border-t-0 md:border-l ${
|
<div className={`flex items-start gap-2.5 border-t px-6 py-5 md:border-t-0 md:border-l ${
|
||||||
isNavyBg ? 'border-white/5 text-slate-400' : 'border-gray-100 text-gray-500'
|
isNavyBg ? 'border-white/5 text-slate-400' : 'border-gray-100 text-gray-500'
|
||||||
}`}>
|
}`}>
|
||||||
<X size={13} className="mt-0.5 shrink-0 text-gray-400" />
|
<Icon icon="ph:x" width={13} className="mt-0.5 shrink-0 text-gray-400" />
|
||||||
{row.saas}
|
{row.saas}
|
||||||
</div>
|
</div>
|
||||||
<div className={`flex items-start gap-2.5 border-t px-6 py-5 md:border-t-0 md:border-l ${
|
<div className={`flex items-start gap-2.5 border-t px-6 py-5 md:border-t-0 md:border-l ${
|
||||||
isNavyBg ? 'border-white/5 text-slate-200' : 'border-gray-100 text-brand-navy'
|
isNavyBg ? 'border-white/5 text-slate-200' : 'border-gray-100 text-brand-navy'
|
||||||
}`}>
|
}`}>
|
||||||
<Check size={13} className={`mt-0.5 shrink-0 ${isNavyBg ? 'text-sky-400' : 'text-brand-blue'}`} />
|
<Icon icon="ph:check" width={13} className={`mt-0.5 shrink-0 ${isNavyBg ? "text-accent" : "text-brand-blue"}`} />
|
||||||
{row.ry}
|
{row.ry}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -83,7 +88,7 @@ export const PlatformAdvantage = ({ isNavyBg }: ThemeProps) => {
|
|||||||
{/* Proof cards */}
|
{/* Proof cards */}
|
||||||
<div className="mt-6 grid gap-4 lg:grid-cols-3">
|
<div className="mt-6 grid gap-4 lg:grid-cols-3">
|
||||||
{proofCards.map((card, index) => {
|
{proofCards.map((card, index) => {
|
||||||
const Icon = card.icon;
|
const cardIcon = card.icon;
|
||||||
return (
|
return (
|
||||||
<motion.article
|
<motion.article
|
||||||
key={card.title}
|
key={card.title}
|
||||||
@@ -98,9 +103,9 @@ export const PlatformAdvantage = ({ isNavyBg }: ThemeProps) => {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className={`mb-5 inline-flex rounded-xl p-3 ${
|
<div className={`mb-5 inline-flex rounded-xl p-3 ${
|
||||||
isNavyBg ? 'bg-brand-blue/15 text-sky-300' : 'bg-brand-blue/8 text-brand-blue'
|
isNavyBg ? 'bg-brand-blue/15 text-accent' : 'bg-brand-blue/8 text-brand-blue'
|
||||||
}`}>
|
}`}>
|
||||||
<Icon size={20} />
|
<Icon icon={cardIcon} width={20} />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="mb-2 font-display text-lg font-bold">{card.title}</h3>
|
<h3 className="mb-2 font-display text-lg font-bold">{card.title}</h3>
|
||||||
<p className={`text-sm leading-relaxed ${isNavyBg ? 'text-slate-400' : 'text-gray-500'}`}>
|
<p className={`text-sm leading-relaxed ${isNavyBg ? 'text-slate-400' : 'text-gray-500'}`}>
|
||||||
+75
-25
@@ -1,26 +1,26 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import Loader from '@/app/components/Loader';
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
import { usePortfolio } from "@/app/portafolio/services/portfolio";
|
import { usePortfolio } from '@/app/(landing)/portafolio/services/portfolio';
|
||||||
import { assetUrl } from "@/app/services/api";
|
import { assetUrl } from '@/app/(landing)/services/api';
|
||||||
import type { ThemeProps } from "@/app/types/ui";
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
|
|
||||||
function PortfolioInner({ isNavyBg }: ThemeProps) {
|
function PortfolioInner({ isNavyBg }: ThemeProps) {
|
||||||
const { data, isLoading } = usePortfolio();
|
const { data, isLoading } = usePortfolio();
|
||||||
|
|
||||||
const bg = isNavyBg ? "#080c14" : "#f0efec";
|
const bg = isNavyBg ? "var(--background)" : "#f9f9f7";
|
||||||
const text = isNavyBg ? "#ffffff" : "#0a0a0a";
|
const text = isNavyBg ? "var(--foreground)" : "#0a0a0a";
|
||||||
const sub = isNavyBg ? "rgba(255,255,255,0.45)" : "#6a6866";
|
const sub = isNavyBg ? "rgba(255,255,255,0.45)" : "#6a6866";
|
||||||
const border = isNavyBg ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)";
|
const border = isNavyBg ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)";
|
||||||
const card = isNavyBg ? "rgba(255,255,255,0.03)" : "#ffffff";
|
const card = isNavyBg ? "rgba(255,255,255,0.03)" : "#ffffff";
|
||||||
const tagBg = isNavyBg ? "rgba(255,255,255,0.07)" : "rgba(0,0,0,0.05)";
|
const tagBg = isNavyBg ? "rgba(255,255,255,0.07)" : "rgba(0,0,0,0.05)";
|
||||||
|
|
||||||
const projects = data ?? [];
|
const projects = data ?? [];
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<section style={{ background: bg, borderBottom: `1px solid ${border}` }} className="px-8 py-28 md:px-14">
|
<section style={{ background: bg }} className="px-8 py-28 md:px-14">
|
||||||
<Loader className="py-20" />
|
<Loader className="py-20" />
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
@@ -32,7 +32,7 @@ function PortfolioInner({ isNavyBg }: ThemeProps) {
|
|||||||
<section
|
<section
|
||||||
id="portafolio"
|
id="portafolio"
|
||||||
aria-labelledby="portfolio-heading"
|
aria-labelledby="portfolio-heading"
|
||||||
style={{ background: bg, borderBottom: `1px solid ${border}` }}
|
style={{ background: bg }}
|
||||||
className="px-8 py-28 md:px-14 transition-colors duration-500"
|
className="px-8 py-28 md:px-14 transition-colors duration-500"
|
||||||
>
|
>
|
||||||
<div className="mx-auto max-w-7xl">
|
<div className="mx-auto max-w-7xl">
|
||||||
@@ -54,25 +54,36 @@ function PortfolioInner({ isNavyBg }: ThemeProps) {
|
|||||||
className="text-headline"
|
className="text-headline"
|
||||||
style={{ maxWidth: "28ch", color: text }}
|
style={{ maxWidth: "28ch", color: text }}
|
||||||
>
|
>
|
||||||
Construimos el sistema. <span style={{ color: "#3b82f6" }}>Tú operas el negocio.</span>
|
Construimos el sistema.{" "}
|
||||||
|
<span style={{ color: "#3b82f6" }}>Tú operas el negocio.</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-4 max-w-xl text-base leading-relaxed" style={{ color: sub }}>
|
<p
|
||||||
Proyectos reales, resultados medibles. Cada implementación parte de entender la operación antes de escribir una sola línea de código.
|
className="mt-4 max-w-xl text-base 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>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||||
{projects.map((p, i) => {
|
{projects.map((p, i) => {
|
||||||
const cover = p.images.find((img) => img.isCover) ?? p.images.sort((a, b) => a.order - b.order)[0];
|
const cover =
|
||||||
|
p.images.find((img) => img.isCover) ??
|
||||||
|
p.images.sort((a, b) => a.order - b.order)[0];
|
||||||
return (
|
return (
|
||||||
<motion.article
|
<motion.article
|
||||||
key={p.id}
|
key={p.id}
|
||||||
initial={{ opacity: 0, y: 24 }}
|
initial={{ opacity: 0, y: 24 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true, margin: "-40px" }}
|
viewport={{ once: true, margin: "-40px" }}
|
||||||
transition={{ duration: 0.55, delay: i * 0.1, ease: [0.22, 1, 0.36, 1] }}
|
transition={{
|
||||||
|
duration: 0.55,
|
||||||
|
delay: i * 0.1,
|
||||||
|
ease: [0.22, 1, 0.36, 1],
|
||||||
|
}}
|
||||||
style={{
|
style={{
|
||||||
borderRadius: 14,
|
borderRadius: 20,
|
||||||
border: `1px solid ${border}`,
|
border: `1px solid ${border}`,
|
||||||
background: card,
|
background: card,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
@@ -85,7 +96,9 @@ function PortfolioInner({ isNavyBg }: ThemeProps) {
|
|||||||
style={{
|
style={{
|
||||||
aspectRatio: "16/9",
|
aspectRatio: "16/9",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
background: isNavyBg ? "rgba(255,255,255,0.04)" : "rgba(0,0,0,0.03)",
|
background: isNavyBg
|
||||||
|
? "rgba(255,255,255,0.04)"
|
||||||
|
: "rgba(0,0,0,0.03)",
|
||||||
borderBottom: `1px solid ${border}`,
|
borderBottom: `1px solid ${border}`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -93,11 +106,31 @@ function PortfolioInner({ isNavyBg }: ThemeProps) {
|
|||||||
<img
|
<img
|
||||||
src={assetUrl(cover.url)}
|
src={assetUrl(cover.url)}
|
||||||
alt={p.title}
|
alt={p.title}
|
||||||
style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }}
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
objectFit: "cover",
|
||||||
|
display: "block",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
|
<div
|
||||||
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke={sub} strokeWidth="1.5">
|
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" />
|
<rect x="3" y="3" width="18" height="18" rx="2" />
|
||||||
<circle cx="8.5" cy="8.5" r="1.5" />
|
<circle cx="8.5" cy="8.5" r="1.5" />
|
||||||
<path d="m21 15-5-5L5 21" />
|
<path d="m21 15-5-5L5 21" />
|
||||||
@@ -107,20 +140,37 @@ function PortfolioInner({ isNavyBg }: ThemeProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div style={{ padding: "24px 24px 28px", display: "flex", flexDirection: "column", flex: 1 }}>
|
<div
|
||||||
|
style={{
|
||||||
|
padding: "24px 24px 28px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{p.clientCompanyName && (
|
{p.clientCompanyName && (
|
||||||
<span className="text-xs font-semibold uppercase tracking-wider mb-2 block" style={{ color: "#3b82f6" }}>
|
<span
|
||||||
|
className="text-xs font-semibold uppercase tracking-wider mb-2 block"
|
||||||
|
style={{ color: "#3b82f6" }}
|
||||||
|
>
|
||||||
{p.clientCompanyName}
|
{p.clientCompanyName}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<h3
|
<h3
|
||||||
className="font-display font-bold mb-3"
|
className="font-display font-bold mb-3"
|
||||||
style={{ fontSize: "1.05rem", color: text, letterSpacing: "-0.01em" }}
|
style={{
|
||||||
|
fontSize: "1.05rem",
|
||||||
|
color: text,
|
||||||
|
letterSpacing: "-0.01em",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{p.title}
|
{p.title}
|
||||||
</h3>
|
</h3>
|
||||||
{p.publicSummary && (
|
{p.publicSummary && (
|
||||||
<p className="text-sm leading-relaxed mb-5" style={{ color: sub }}>
|
<p
|
||||||
|
className="text-sm leading-relaxed mb-5"
|
||||||
|
style={{ color: sub }}
|
||||||
|
>
|
||||||
{p.publicSummary}
|
{p.publicSummary}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
+5
-5
@@ -1,11 +1,11 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
import { principles } from '@/app/home/data/principlesData';
|
import { principles } from '@/app/(landing)/home/data/principlesData';
|
||||||
|
|
||||||
export const Principles = ({ isNavyBg }: ThemeProps) => {
|
export const Principles = ({ isNavyBg }: ThemeProps) => {
|
||||||
const bg = isNavyBg ? '#0d1117' : '#f5f5f3';
|
const bg = isNavyBg ? 'var(--background)' : '#f5f5f3';
|
||||||
const text = isNavyBg ? '#eef0f4' : '#0a0a0a';
|
const text = isNavyBg ? 'var(--foreground)' : '#0a0a0a';
|
||||||
const sub = isNavyBg ? 'rgba(255,255,255,0.4)' : 'rgba(0,0,0,0.4)';
|
const sub = isNavyBg ? 'rgba(255,255,255,0.4)' : 'rgba(0,0,0,0.4)';
|
||||||
const gridGap = isNavyBg ? 'rgba(255,255,255,0.07)' : 'rgba(0,0,0,0.07)';
|
const gridGap = isNavyBg ? 'rgba(255,255,255,0.07)' : 'rgba(0,0,0,0.07)';
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ export const Principles = ({ isNavyBg }: ThemeProps) => {
|
|||||||
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5"
|
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5"
|
||||||
style={{
|
style={{
|
||||||
border: `1px solid ${gridGap}`,
|
border: `1px solid ${gridGap}`,
|
||||||
borderRadius: 4,
|
borderRadius: 20,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
'use client';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
|
|
||||||
|
const symptoms = [
|
||||||
|
{ icon: 'ph:lock', label: 'Software que impone sus reglas', detail: 'en vez de adaptarse a cómo operas' },
|
||||||
|
{ icon: 'ph:shuffle', label: 'Procesos que siguen siendo manuales', detail: 'porque nadie los diseñó para escalar' },
|
||||||
|
{ icon: 'ph:eye-slash', label: 'Sin visibilidad real', detail: 'decisiones a ciegas sobre lo que pasa en el negocio' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const Problem = ({ isNavyBg }: ThemeProps) => {
|
||||||
|
const text = isNavyBg ? 'var(--foreground)' : '#0a0a0a';
|
||||||
|
const sub = isNavyBg ? 'rgba(255,255,255,0.45)' : 'rgba(0,0,0,0.4)';
|
||||||
|
const border = isNavyBg ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.08)';
|
||||||
|
const cardBg = isNavyBg ? 'rgba(255,255,255,0.04)' : 'rgba(255,255,255,0.8)';
|
||||||
|
const rowBdr = isNavyBg ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.06)';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
aria-labelledby="problem-heading"
|
||||||
|
className="relative px-8 py-16 md:px-14 transition-colors duration-500"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute inset-0 bg-dot-grid text-border opacity-40"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute -right-32 -top-24 h-[24rem] w-[24rem] rounded-full blur-[110px]"
|
||||||
|
style={{ background: 'rgba(139,92,246,0.12)' }}
|
||||||
|
/>
|
||||||
|
<div className="relative mx-auto grid max-w-7xl gap-16 lg:grid-cols-[1.1fr_0.9fr] lg:items-center">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 28 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: false, amount: 0.15 }}
|
||||||
|
transition={{ duration: 0.65, ease: [0.22, 1, 0.36, 1] }}
|
||||||
|
>
|
||||||
|
<h2
|
||||||
|
id="problem-heading"
|
||||||
|
className="text-display"
|
||||||
|
style={{ lineHeight: 1.0, letterSpacing: '-0.02em', color: text }}
|
||||||
|
>
|
||||||
|
{['La mayoría', 'de los problemas', 'operativos son'].map((line, i) => (
|
||||||
|
<motion.span
|
||||||
|
key={line}
|
||||||
|
className="block"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.6, delay: i * 0.07, ease: [0.22, 1, 0.36, 1] }}
|
||||||
|
>
|
||||||
|
{line}
|
||||||
|
</motion.span>
|
||||||
|
))}
|
||||||
|
<motion.span
|
||||||
|
className="block text-brand-red"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.24, ease: [0.22, 1, 0.36, 1] }}
|
||||||
|
>
|
||||||
|
problemas de sistema.
|
||||||
|
</motion.span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 24, scale: 0.97 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0, scale: 1 }}
|
||||||
|
viewport={{ once: true, amount: 0.3 }}
|
||||||
|
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
|
||||||
|
className="relative rounded-[28px] p-2"
|
||||||
|
style={{ background: cardBg, border: `1px solid ${border}`, backdropFilter: 'blur(12px)' }}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
{symptoms.map((s, i) => (
|
||||||
|
<motion.div
|
||||||
|
key={s.label}
|
||||||
|
initial={{ opacity: 0, x: 16 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.45, delay: 0.15 + i * 0.1, ease: [0.22, 1, 0.36, 1] }}
|
||||||
|
className="flex items-center gap-4 rounded-3xl px-5 py-5"
|
||||||
|
style={{ borderBottom: i < symptoms.length - 1 ? `1px solid ${rowBdr}` : 'none' }}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl"
|
||||||
|
style={{ background: 'rgba(59,130,246,0.12)', color: '#3b82f6' }}
|
||||||
|
>
|
||||||
|
<Icon icon={s.icon} width={19} />
|
||||||
|
</span>
|
||||||
|
<div className="min-w-0">
|
||||||
|
<p className="text-sm font-bold" style={{ color: text }}>{s.label}</p>
|
||||||
|
<p className="mt-0.5 text-xs leading-snug" style={{ color: sub }}>{s.detail}</p>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
import { processSteps as steps } from '@/app/home/data/processData';
|
import { processSteps as steps } from '@/app/(landing)/home/data/processData';
|
||||||
|
|
||||||
export const Process = ({ isNavyBg }: ThemeProps) => {
|
export const Process = ({ isNavyBg }: ThemeProps) => {
|
||||||
const bg = isNavyBg ? '#001f5b' : '#ffffff';
|
const bg = isNavyBg ? 'var(--background)' : '#ffffff';
|
||||||
const text = isNavyBg ? '#ffffff' : '#0a0a0a';
|
const text = isNavyBg ? 'var(--foreground)' : '#0a0a0a';
|
||||||
const sub = isNavyBg ? 'rgba(255,255,255,0.4)' : '#6a6866';
|
const sub = isNavyBg ? 'rgba(255,255,255,0.4)' : '#6a6866';
|
||||||
const border = isNavyBg ? 'rgba(255,255,255,0.1)' : '#dddbd5';
|
const border = isNavyBg ? 'rgba(255,255,255,0.1)' : '#dddbd5';
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ export const Process = ({ isNavyBg }: ThemeProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Steps */}
|
{/* Steps */}
|
||||||
<div className="grid gap-0 md:grid-cols-3 lg:grid-cols-5" style={{ border: `1px solid ${border}`, borderRadius: 4, overflow: 'hidden' }}>
|
<div className="grid gap-0 md:grid-cols-3 lg:grid-cols-5" style={{ border: `1px solid ${border}`, borderRadius: 20, overflow: 'hidden' }}>
|
||||||
{steps.map((step, i) => (
|
{steps.map((step, i) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={step.num}
|
key={step.num}
|
||||||
@@ -1,26 +1,25 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { Check } from 'lucide-react';
|
import { Icon } from '@iconify/react';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
import { servicesData } from '@/app/home/data/servicesData';
|
import { servicesData } from '@/app/(landing)/home/data/servicesData';
|
||||||
|
|
||||||
export const Services = ({ isNavyBg }: ThemeProps) => {
|
export const Services = ({ isNavyBg }: ThemeProps) => {
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
id="servicios"
|
id="servicios"
|
||||||
className={`section-wave px-6 py-28 md:px-12 transition-colors duration-500 ${
|
className={`relative px-6 py-20 md:px-12 transition-colors duration-500 ${
|
||||||
isNavyBg ? 'bg-[#001749] text-white' : 'bg-slate-50 text-brand-black'
|
isNavyBg ? 'text-[var(--foreground)]' : 'text-brand-black'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="mx-auto max-w-7xl">
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute inset-0 bg-dot-grid text-border opacity-40"
|
||||||
|
/>
|
||||||
|
<div className="relative mx-auto max-w-7xl">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="mb-16 flex flex-col justify-between gap-8 md:flex-row md:items-end">
|
<div className="mb-10 flex flex-col justify-between gap-8 md:flex-row md:items-end">
|
||||||
<div>
|
<div>
|
||||||
<span className={`mb-3 block text-xs font-semibold uppercase tracking-[0.14em] ${
|
|
||||||
isNavyBg ? 'text-sky-400' : 'text-brand-blue'
|
|
||||||
}`}>
|
|
||||||
Servicios
|
|
||||||
</span>
|
|
||||||
<h2 className="max-w-2xl text-section-title">
|
<h2 className="max-w-2xl text-section-title">
|
||||||
Soluciones que conectan producto, infraestructura y crecimiento.
|
Soluciones que conectan producto, infraestructura y crecimiento.
|
||||||
</h2>
|
</h2>
|
||||||
@@ -33,10 +32,10 @@ export const Services = ({ isNavyBg }: ThemeProps) => {
|
|||||||
{/* Cards grid */}
|
{/* Cards grid */}
|
||||||
<div className="grid gap-4 md:grid-cols-12">
|
<div className="grid gap-4 md:grid-cols-12">
|
||||||
{servicesData.map((service, index) => {
|
{servicesData.map((service, index) => {
|
||||||
const Icon = service.icon;
|
const serviceIcon = service.icon;
|
||||||
const accentClass = service.accent === 'blue' ? 'bg-brand-blue' : 'bg-brand-red';
|
const accentClass = service.accent === 'blue' ? 'bg-brand-blue' : 'bg-brand-red';
|
||||||
const iconBgClass = service.accent === 'blue'
|
const iconBgClass = service.accent === 'blue'
|
||||||
? (isNavyBg ? 'bg-brand-blue/15 text-sky-300' : 'bg-brand-blue/10 text-brand-blue')
|
? (isNavyBg ? 'bg-brand-blue/15 text-accent' : 'bg-brand-blue/10 text-brand-blue')
|
||||||
: (isNavyBg ? 'bg-brand-red/15 text-blue-300' : 'bg-brand-red/10 text-brand-red');
|
: (isNavyBg ? 'bg-brand-red/15 text-blue-300' : 'bg-brand-red/10 text-brand-red');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -58,7 +57,7 @@ export const Services = ({ isNavyBg }: ThemeProps) => {
|
|||||||
{/* Header row */}
|
{/* Header row */}
|
||||||
<div className="mb-6 flex items-start justify-between">
|
<div className="mb-6 flex items-start justify-between">
|
||||||
<div className={`rounded-xl p-3 ${iconBgClass}`}>
|
<div className={`rounded-xl p-3 ${iconBgClass}`}>
|
||||||
<Icon size={22} />
|
<Icon icon={serviceIcon} width={22} />
|
||||||
</div>
|
</div>
|
||||||
<span className={`font-mono text-xs font-bold ${isNavyBg ? 'text-white/20' : 'text-gray-200'}`}>
|
<span className={`font-mono text-xs font-bold ${isNavyBg ? 'text-white/20' : 'text-gray-200'}`}>
|
||||||
0{service.id}
|
0{service.id}
|
||||||
@@ -74,10 +73,11 @@ export const Services = ({ isNavyBg }: ThemeProps) => {
|
|||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{service.features.map((f: string) => (
|
{service.features.map((f: string) => (
|
||||||
<li key={f} className="flex items-center gap-2.5">
|
<li key={f} className="flex items-center gap-2.5">
|
||||||
<Check
|
<Icon
|
||||||
size={13}
|
icon="ph:check"
|
||||||
|
width={13}
|
||||||
className={`shrink-0 ${service.accent === 'blue'
|
className={`shrink-0 ${service.accent === 'blue'
|
||||||
? (isNavyBg ? 'text-sky-400' : 'text-brand-blue')
|
? (isNavyBg ? 'text-accent' : 'text-brand-blue')
|
||||||
: (isNavyBg ? 'text-blue-400' : 'text-brand-red')
|
: (isNavyBg ? 'text-blue-400' : 'text-brand-red')
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import type { ThemeProps } from '@/app/types/ui';
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
import { stackGroups } from '@/app/home/data/stackData';
|
import { stackGroups } from '@/app/(landing)/home/data/stackData';
|
||||||
|
|
||||||
export const Stack = ({ isNavyBg }: ThemeProps) => {
|
export const Stack = ({ isNavyBg }: ThemeProps) => {
|
||||||
const bg = isNavyBg ? '#0f1520' : '#f9f9f7';
|
const bg = isNavyBg ? '#0f1520' : '#f9f9f7';
|
||||||
File renamed without changes.
+7
-7
@@ -1,9 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import Loader from '@/app/components/Loader';
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
import { useTestimonials } from "@/app/home/services/testimonials";
|
import { useTestimonials } from '@/app/(landing)/home/services/testimonials';
|
||||||
import type { ThemeProps } from "@/app/types/ui";
|
import type { ThemeProps } from '@/app/(landing)/types/ui';
|
||||||
|
|
||||||
export const Testimonial = ({ isNavyBg }: ThemeProps) => {
|
export const Testimonial = ({ isNavyBg }: ThemeProps) => {
|
||||||
const { data, isLoading } = useTestimonials();
|
const { data, isLoading } = useTestimonials();
|
||||||
@@ -21,17 +21,17 @@ export const Testimonial = ({ isNavyBg }: ThemeProps) => {
|
|||||||
}, [testimonials.length]);
|
}, [testimonials.length]);
|
||||||
|
|
||||||
const item = testimonials[current];
|
const item = testimonials[current];
|
||||||
const bg = isNavyBg ? "#001f5b" : "#ffffff";
|
const bg = isNavyBg ? "var(--background)" : "#f9f9f7";
|
||||||
const border = isNavyBg ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)";
|
const border = isNavyBg ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)";
|
||||||
const sub = isNavyBg ? "rgba(255,255,255,0.45)" : "#6a6866";
|
const sub = isNavyBg ? "rgba(255,255,255,0.45)" : "#6a6866";
|
||||||
const text = isNavyBg ? "#ffffff" : "#0a0a0a";
|
const text = isNavyBg ? "var(--foreground)" : "#0a0a0a";
|
||||||
|
|
||||||
if (!isLoading && testimonials.length === 0) return null; // sección se oculta si no hay testimonios
|
if (!isLoading && testimonials.length === 0) return null; // sección se oculta si no hay testimonios
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
aria-label="Testimonios de clientes"
|
aria-label="Testimonios de clientes"
|
||||||
style={{ background: bg, borderBottom: `1px solid ${border}` }}
|
style={{ background: bg }}
|
||||||
className="px-8 py-24 md:px-14 transition-colors duration-500"
|
className="px-8 py-24 md:px-14 transition-colors duration-500"
|
||||||
>
|
>
|
||||||
<div className="mx-auto max-w-4xl">
|
<div className="mx-auto max-w-4xl">
|
||||||
@@ -101,7 +101,7 @@ export const Testimonial = ({ isNavyBg }: ThemeProps) => {
|
|||||||
style={{
|
style={{
|
||||||
width: i === current ? 24 : 8,
|
width: i === current ? 24 : 8,
|
||||||
height: 8,
|
height: 8,
|
||||||
borderRadius: 4,
|
borderRadius: 20,
|
||||||
background: i === current ? "#3b82f6" : sub,
|
background: i === current ? "#3b82f6" : sub,
|
||||||
border: "none",
|
border: "none",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { apiFetch } from '@/app/(landing)/services/api';
|
||||||
|
|
||||||
|
export interface Company {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
logoUrl?: string;
|
||||||
|
showInLanding?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCompanies() {
|
||||||
|
return useQuery<Company[]>({
|
||||||
|
queryKey: ["companies"],
|
||||||
|
queryFn: () => apiFetch<Company[]>("/api/companies"),
|
||||||
|
staleTime: 1000 * 60 * 5,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { apiFetch } from '@/app/(landing)/services/api';
|
||||||
|
|
||||||
|
export interface TechPartner {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
logoUrl?: string;
|
||||||
|
category?: string;
|
||||||
|
websiteUrl?: string;
|
||||||
|
displayOrder: number;
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTechPartners() {
|
||||||
|
return useQuery<TechPartner[]>({
|
||||||
|
queryKey: ["tech-partners"],
|
||||||
|
queryFn: () => apiFetch<TechPartner[]>("/api/tech-partners"),
|
||||||
|
staleTime: 1000 * 60 * 5,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { apiFetch } from '@/app/(landing)/services/api';
|
||||||
|
|
||||||
|
interface OnboardingCompleted {
|
||||||
|
clientCompanyName: string;
|
||||||
|
testimonialQuote?: string;
|
||||||
|
testimonialAuthor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Testimonial {
|
||||||
|
quote: string;
|
||||||
|
author: string;
|
||||||
|
company: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTestimonials() {
|
||||||
|
return useQuery<Testimonial[]>({
|
||||||
|
queryKey: ["testimonials"],
|
||||||
|
queryFn: async () => {
|
||||||
|
const data = await apiFetch<OnboardingCompleted[]>(
|
||||||
|
"/api/onboarding/completed",
|
||||||
|
);
|
||||||
|
return data
|
||||||
|
.filter((o) => o.testimonialQuote)
|
||||||
|
.map((o) => ({
|
||||||
|
quote: o.testimonialQuote!,
|
||||||
|
author: o.testimonialAuthor ?? "",
|
||||||
|
company: o.clientCompanyName,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
staleTime: 1000 * 60 * 5,
|
||||||
|
});
|
||||||
|
}
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,20 @@
|
|||||||
|
'use client';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export function useIsDark() {
|
||||||
|
const [isDark, setIsDark] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const root = document.documentElement;
|
||||||
|
setIsDark(root.classList.contains('dark'));
|
||||||
|
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
setIsDark(root.classList.contains('dark'));
|
||||||
|
});
|
||||||
|
observer.observe(root, { attributes: true, attributeFilter: ['class'] });
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return isDark;
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,10 @@
|
|||||||
|
import { Providers } from './providers';
|
||||||
|
import { AppShell } from './components/AppShell';
|
||||||
|
|
||||||
|
export default function LandingLayout({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<Providers>
|
||||||
|
<AppShell>{children}</AppShell>
|
||||||
|
</Providers>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { clsx, type ClassValue } from "clsx"
|
||||||
|
import { twMerge } from "tailwind-merge"
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-dvh items-center justify-center" style={{ background: 'var(--background)' }}>
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -1,5 +1,5 @@
|
|||||||
import type { Metadata } from 'next';
|
import type { Metadata } from 'next';
|
||||||
import { HomePage } from '@/app/home/HomePage';
|
import { HomePage } from '@/app/(landing)/home/HomePage';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Rynext Technologies | Software Empresarial 100% Mexicano',
|
title: 'Rynext Technologies | Software Empresarial 100% Mexicano',
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
"use client";
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
|
import { usePortfolio } from '@/app/(landing)/portafolio/services/portfolio';
|
||||||
|
import { assetUrl } from '@/app/(landing)/services/api';
|
||||||
|
|
||||||
|
const bg = "var(--background)";
|
||||||
|
const text = "var(--foreground)";
|
||||||
|
const sub = "var(--muted-foreground)";
|
||||||
|
const border = "var(--border)";
|
||||||
|
const card = "var(--card)";
|
||||||
|
const tagBg = "rgba(59,130,246,0.08)";
|
||||||
|
|
||||||
|
function PortafolioContent() {
|
||||||
|
const { data, isLoading } = usePortfolio();
|
||||||
|
const projects = data ?? [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main id="main-content">
|
||||||
|
{/* Hero */}
|
||||||
|
<section
|
||||||
|
style={{ background: bg, paddingTop: 120, paddingBottom: 16 }}
|
||||||
|
className="px-8 md:px-14"
|
||||||
|
>
|
||||||
|
<div className="mx-auto max-w-7xl text-center">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.65, ease: [0.22, 1, 0.36, 1] }}
|
||||||
|
>
|
||||||
|
<h1
|
||||||
|
className="text-2xl md:text-3xl font-bold"
|
||||||
|
style={{ color: text }}
|
||||||
|
>
|
||||||
|
Casos de éxito
|
||||||
|
</h1>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Grid */}
|
||||||
|
<section style={{ background: bg }} className="px-8 pt-0 pb-20 md:px-14">
|
||||||
|
<div className="mx-auto max-w-7xl">
|
||||||
|
{isLoading ? (
|
||||||
|
<Loader className="py-20" />
|
||||||
|
) : 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 }}
|
||||||
|
whileHover={{ y: -4 }}
|
||||||
|
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",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={`/portafolio/${p.id}`}
|
||||||
|
style={{ display: "flex", flexDirection: "column", flex: 1, textDecoration: "none" }}
|
||||||
|
>
|
||||||
|
{/* 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>
|
||||||
|
</Link>
|
||||||
|
</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-dvh items-center justify-center"
|
||||||
|
style={{ background: bg }}
|
||||||
|
>
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return <PortafolioContent />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
"use client";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useParams, useRouter } from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import { usePortfolio } from "@/app/(landing)/portafolio/services/portfolio";
|
||||||
|
import { assetUrl } from "@/app/(landing)/services/api";
|
||||||
|
import Loader from "@/app/(landing)/components/Loader";
|
||||||
|
|
||||||
|
function siteHref(url: string) {
|
||||||
|
return /^https?:\/\//i.test(url) ? url : `https://${url}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function siteLabel(url: string) {
|
||||||
|
const host = url.replace(/^https?:\/\//i, "").replace(/\/$/, "");
|
||||||
|
return /^www\./i.test(host) ? host : `www.${host}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderRichText(content: string) {
|
||||||
|
return content.split("\n").map((line, i) => {
|
||||||
|
if (line.startsWith("# "))
|
||||||
|
return (
|
||||||
|
<h2 key={i} style={{ fontSize: "1.5rem", fontWeight: 700, color: "var(--foreground)", marginTop: "2rem", marginBottom: "0.5rem", lineHeight: 1.3 }}>
|
||||||
|
{line.slice(2)}
|
||||||
|
</h2>
|
||||||
|
);
|
||||||
|
if (line.startsWith("## "))
|
||||||
|
return (
|
||||||
|
<h3 key={i} style={{ fontSize: "1.15rem", fontWeight: 600, color: "var(--foreground)", marginTop: "1.5rem", marginBottom: "0.4rem" }}>
|
||||||
|
{line.slice(3)}
|
||||||
|
</h3>
|
||||||
|
);
|
||||||
|
if (line.startsWith("- "))
|
||||||
|
return (
|
||||||
|
<li key={i} style={{ color: "var(--muted-foreground)", lineHeight: 1.8, marginLeft: "1.2rem", listStyleType: "disc" }}>
|
||||||
|
{line.slice(2)}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
if (line.trim() === "") return <br key={i} />;
|
||||||
|
return (
|
||||||
|
<p key={i} style={{ color: "var(--muted-foreground)", lineHeight: 1.85, marginBottom: "0.25rem" }}>
|
||||||
|
{line}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CaseStudyPage() {
|
||||||
|
const params = useParams();
|
||||||
|
const router = useRouter();
|
||||||
|
const id = typeof params.id === "string" ? params.id : (params.id?.[0] ?? "");
|
||||||
|
|
||||||
|
const { data: projects, isLoading, isError } = usePortfolio();
|
||||||
|
const project = projects?.find((p) => p.id === id);
|
||||||
|
|
||||||
|
const [activeImage, setActiveImage] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (project) document.title = `${project.title} | Portafolio`;
|
||||||
|
}, [project]);
|
||||||
|
|
||||||
|
if (isLoading) return <Loader className="py-40" />;
|
||||||
|
|
||||||
|
if (isError || !project) {
|
||||||
|
return (
|
||||||
|
<main style={{ minHeight: "80vh", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 16 }}>
|
||||||
|
<p style={{ color: "var(--muted-foreground)", fontSize: 14, fontFamily: "monospace", letterSpacing: "0.1em" }}>
|
||||||
|
CASO NO ENCONTRADO
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={() => router.push("/portafolio")}
|
||||||
|
style={{ color: "#3b82f6", fontSize: 14, textDecoration: "underline", background: "none", border: "none", cursor: "pointer" }}
|
||||||
|
>
|
||||||
|
Volver al portafolio
|
||||||
|
</button>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const images = [...project.images].sort((a, b) => a.order - b.order);
|
||||||
|
const cover = images.find((img) => img.isCover) ?? images[0];
|
||||||
|
const gallery = images.length > 0 ? images : cover ? [cover] : [];
|
||||||
|
const activeUrl = assetUrl(gallery[activeImage]?.url ?? cover?.url);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main id="main-content">
|
||||||
|
{/* Hero */}
|
||||||
|
<section style={{ background: "var(--background)", paddingTop: "140px", paddingBottom: "60px" }} className="px-8 md:px-14">
|
||||||
|
<div className="mx-auto" style={{ maxWidth: "900px" }}>
|
||||||
|
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5 }}>
|
||||||
|
{/* Volver */}
|
||||||
|
<Link
|
||||||
|
href="/portafolio"
|
||||||
|
style={{ display: "inline-flex", alignItems: "center", gap: 8, marginBottom: 20, fontFamily: "monospace", fontSize: 11, letterSpacing: "0.14em", color: "#3b82f6", textDecoration: "none" }}
|
||||||
|
>
|
||||||
|
← VOLVER AL PORTAFOLIO
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{project.clientCompanyName && (
|
||||||
|
<div style={{ marginBottom: 20, fontFamily: "monospace", fontSize: 11, letterSpacing: "0.14em", color: "var(--muted-foreground)" }}>
|
||||||
|
{project.clientCompanyName.toUpperCase()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Título */}
|
||||||
|
<h1 style={{ fontSize: "clamp(1.8rem, 4vw, 2.8rem)", fontWeight: 700, color: "var(--foreground)", lineHeight: 1.2, marginBottom: 20 }}>
|
||||||
|
{project.title}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{/* Resumen */}
|
||||||
|
{project.publicSummary && (
|
||||||
|
<p style={{ fontSize: "1.1rem", color: "var(--muted-foreground)", lineHeight: 1.7, marginBottom: 28, borderLeft: "3px solid var(--border)", paddingLeft: 16 }}>
|
||||||
|
{project.publicSummary}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Meta: tecnologías + sitio */}
|
||||||
|
<div style={{ display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap", paddingTop: 20, borderTop: "1px solid var(--border)" }}>
|
||||||
|
{project.technologies.length > 0 && (
|
||||||
|
<div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
|
||||||
|
{project.technologies.map((t) => (
|
||||||
|
<span
|
||||||
|
key={t.id}
|
||||||
|
style={{
|
||||||
|
fontSize: 10.5, fontWeight: 600, padding: "3px 9px", borderRadius: 99,
|
||||||
|
background: "rgba(59,130,246,0.08)", color: t.color ?? "var(--muted-foreground)", letterSpacing: "0.01em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t.name}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{project.siteUrl && (
|
||||||
|
<a
|
||||||
|
href={siteHref(project.siteUrl)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 13, color: "#3b82f6", textDecoration: "none", marginLeft: "auto" }}
|
||||||
|
>
|
||||||
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||||
|
<circle cx="12" cy="12" r="10" />
|
||||||
|
<path d="M2 12h20M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20Z" />
|
||||||
|
</svg>
|
||||||
|
{siteLabel(project.siteUrl)}
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Galería */}
|
||||||
|
{activeUrl && (
|
||||||
|
<div style={{ background: "var(--muted)", borderBottom: "1px solid var(--border)" }}>
|
||||||
|
<div className="mx-auto" style={{ maxWidth: "1100px", padding: "0 2rem" }}>
|
||||||
|
<motion.div
|
||||||
|
key={activeUrl}
|
||||||
|
initial={{ opacity: 0, scale: 0.98 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
transition={{ duration: 0.4 }}
|
||||||
|
style={{ overflow: "hidden", borderRadius: 4, aspectRatio: "16/7", marginTop: -1 }}
|
||||||
|
>
|
||||||
|
<img src={activeUrl} alt={project.title} style={{ width: "100%", height: "100%", objectFit: "cover" }} />
|
||||||
|
</motion.div>
|
||||||
|
{gallery.length > 1 && (
|
||||||
|
<div style={{ display: "flex", gap: 10, padding: "16px 0 24px" }}>
|
||||||
|
{gallery.map((img, i) => (
|
||||||
|
<button
|
||||||
|
key={img.id}
|
||||||
|
onClick={() => setActiveImage(i)}
|
||||||
|
style={{
|
||||||
|
width: 72, height: 48, borderRadius: 4, overflow: "hidden", padding: 0, cursor: "pointer",
|
||||||
|
border: i === activeImage ? "2px solid #3b82f6" : "2px solid transparent",
|
||||||
|
opacity: i === activeImage ? 1 : 0.6,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img src={assetUrl(img.url)} alt="" style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }} />
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Caso de estudio + solución */}
|
||||||
|
<section style={{ background: "var(--background)", padding: "80px 0" }} className="px-8 md:px-14">
|
||||||
|
<motion.div
|
||||||
|
className="mx-auto"
|
||||||
|
style={{ maxWidth: "780px" }}
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.6, delay: 0.2 }}
|
||||||
|
>
|
||||||
|
{project.caseStudy && (
|
||||||
|
<div style={{ background: "var(--card)", border: "1px solid var(--border)", borderRadius: 4, padding: "48px 52px", fontSize: "1rem", lineHeight: 1.85, marginBottom: project.solution ? 32 : 0 }}>
|
||||||
|
<span style={{ fontFamily: "monospace", fontSize: 10, letterSpacing: "0.14em", color: "var(--muted-foreground)" }}>
|
||||||
|
CASO DE ESTUDIO
|
||||||
|
</span>
|
||||||
|
<div style={{ marginTop: 8 }}>{renderRichText(project.caseStudy)}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{project.solution && (
|
||||||
|
<div style={{ background: "var(--card)", border: "1px solid var(--border)", borderRadius: 4, padding: "48px 52px", fontSize: "1rem", lineHeight: 1.85 }}>
|
||||||
|
<span style={{ fontFamily: "monospace", fontSize: 10, letterSpacing: "0.14em", color: "var(--muted-foreground)" }}>
|
||||||
|
SOLUCIÓN
|
||||||
|
</span>
|
||||||
|
<div style={{ marginTop: 8 }}>{renderRichText(project.solution)}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!project.caseStudy && !project.solution && (
|
||||||
|
<p style={{ color: "var(--muted-foreground)", fontSize: 14 }}>
|
||||||
|
Aún no hay detalle publicado para este caso.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</motion.div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
import CaseStudyPage from "./CaseStudyPage";
|
||||||
|
import { API_URL, assetUrl } from "@/app/(landing)/services/api";
|
||||||
|
import type { PortfolioProject } from "@/app/(landing)/portafolio/types/portfolio";
|
||||||
|
|
||||||
|
const BASE_URL = "https://rynext.com.mx";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* null = la API respondió pero el caso no existe/no está publicado (404 real).
|
||||||
|
* undefined = no se pudo consultar la API (red, TLS local, etc.) — no es un 404,
|
||||||
|
* se deja que el cliente (CaseStudyPage) resuelva con su propio fetch.
|
||||||
|
*/
|
||||||
|
async function getProject(id: string): Promise<PortfolioProject | null | undefined> {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API_URL}/api/portfolio/public`, {
|
||||||
|
next: { revalidate: 3600 },
|
||||||
|
});
|
||||||
|
if (!res.ok) return undefined;
|
||||||
|
const projects = (await res.json()) as PortfolioProject[];
|
||||||
|
return projects.find((p) => p.id === id) ?? null;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = { params: Promise<{ id: string }> };
|
||||||
|
|
||||||
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||||
|
const { id } = await params;
|
||||||
|
const project = await getProject(id);
|
||||||
|
|
||||||
|
if (!project) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `${BASE_URL}/portafolio/${project.id}`;
|
||||||
|
const cover =
|
||||||
|
project.images.find((img) => img.isCover) ??
|
||||||
|
[...project.images].sort((a, b) => a.order - b.order)[0];
|
||||||
|
const image = assetUrl(cover?.url);
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: `${project.title} | Portafolio | Rynext Technologies`,
|
||||||
|
description: project.publicSummary,
|
||||||
|
alternates: { canonical: url },
|
||||||
|
openGraph: {
|
||||||
|
title: project.title,
|
||||||
|
description: project.publicSummary,
|
||||||
|
type: "article",
|
||||||
|
url,
|
||||||
|
images: image
|
||||||
|
? [{ url: image, width: 1200, height: 630, alt: project.title }]
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary_large_image",
|
||||||
|
title: project.title,
|
||||||
|
description: project.publicSummary,
|
||||||
|
images: image ? [image] : undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Page({ params }: Props) {
|
||||||
|
const { id } = await params;
|
||||||
|
const project = await getProject(id);
|
||||||
|
|
||||||
|
// Solo 404 cuando confirmamos que no existe; si la API no respondió,
|
||||||
|
// dejamos que CaseStudyPage lo resuelva del lado del cliente.
|
||||||
|
if (project === null) notFound();
|
||||||
|
|
||||||
|
return <CaseStudyPage />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-dvh items-center justify-center" style={{ background: 'var(--background)' }}>
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,40 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { apiFetch } from '@/app/(landing)/services/api';
|
||||||
|
|
||||||
|
export interface PortfolioImage {
|
||||||
|
id: string;
|
||||||
|
portfolioEntryId: string;
|
||||||
|
url: string;
|
||||||
|
order: number;
|
||||||
|
isCover: boolean;
|
||||||
|
caption?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PortfolioTechnology {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
iconUrl?: string;
|
||||||
|
color?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PortfolioProject {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
clientCompanyName?: string;
|
||||||
|
publicSummary?: string;
|
||||||
|
caseStudy?: string;
|
||||||
|
solution?: string;
|
||||||
|
siteUrl?: string;
|
||||||
|
isPublished: boolean;
|
||||||
|
displayOrder: number;
|
||||||
|
technologies: PortfolioTechnology[];
|
||||||
|
images: PortfolioImage[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function usePortfolio() {
|
||||||
|
return useQuery<PortfolioProject[]>({
|
||||||
|
queryKey: ["portfolio"],
|
||||||
|
queryFn: () => apiFetch<PortfolioProject[]>("/api/portfolio/public"),
|
||||||
|
staleTime: 1000 * 60 * 5,
|
||||||
|
});
|
||||||
|
}
|
||||||
File renamed without changes.
+3
-4
@@ -9,21 +9,20 @@ export function PrivacidadPage() {
|
|||||||
return (
|
return (
|
||||||
<main
|
<main
|
||||||
id="main-content"
|
id="main-content"
|
||||||
style={{ background: "#ffffff", minHeight: "100vh" }}
|
style={{ background: "var(--background)", minHeight: "100vh" }}
|
||||||
>
|
>
|
||||||
<section
|
<section
|
||||||
style={{
|
style={{
|
||||||
paddingTop: "140px",
|
paddingTop: "140px",
|
||||||
paddingBottom: "100px",
|
paddingBottom: "100px",
|
||||||
borderBottom: "1px solid #dddbd5",
|
|
||||||
}}
|
}}
|
||||||
className="px-8 md:px-14"
|
className="px-8 md:px-14"
|
||||||
>
|
>
|
||||||
<div className="mx-auto max-w-3xl">
|
<div className="mx-auto max-w-3xl">
|
||||||
<h1 className="text-headline mb-4" style={{ color: "#0a0a0a" }}>
|
<h1 className="text-headline mb-4" style={{ color: "var(--foreground)" }}>
|
||||||
Aviso de Privacidad Integral
|
Aviso de Privacidad Integral
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-sm mb-16" style={{ color: "#aaa8a4" }}>
|
<p className="text-sm mb-16" style={{ color: "var(--muted-foreground)" }}>
|
||||||
Última actualización: agosto de 2026
|
Última actualización: agosto de 2026
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-dvh items-center justify-center" style={{ background: 'var(--background)' }}>
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
File renamed without changes.
File renamed without changes.
@@ -1,7 +1,7 @@
|
|||||||
export const API_URL = process.env.NEXT_PUBLIC_API_URL ?? "https://localhost:7030";
|
export const API_URL = process.env.NEXT_PUBLIC_API_URL ?? "https://localhost:7030";
|
||||||
|
|
||||||
export async function apiFetch<T>(path: string): Promise<T> {
|
export async function apiFetch<T>(path: string): Promise<T> {
|
||||||
const res = await fetch(`${API_URL}${path}`);
|
const res = await fetch(`${API_URL}${path}`, { signal: AbortSignal.timeout(8000) });
|
||||||
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
||||||
return res.json() as Promise<T>;
|
return res.json() as Promise<T>;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,434 @@
|
|||||||
|
"use client";
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import { Icon } from "@iconify/react";
|
||||||
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
|
import { useTeam, groupByDepartment } from '@/app/(landing)/sobre-nosotros/services/team';
|
||||||
|
import { valores } from "@/app/(landing)/home/data/sobreNosotrosData";
|
||||||
|
|
||||||
|
const TEAM_IMAGE =
|
||||||
|
"https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=1200&q=80";
|
||||||
|
|
||||||
|
const VALOR_ICONS: string[] = [
|
||||||
|
"ph:stack",
|
||||||
|
"ph:shield-check",
|
||||||
|
"ph:file-code",
|
||||||
|
"ph:arrows-clockwise",
|
||||||
|
"ph:seal-check",
|
||||||
|
];
|
||||||
|
|
||||||
|
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: "var(--background)",
|
||||||
|
paddingTop: "140px",
|
||||||
|
paddingBottom: "100px",
|
||||||
|
}}
|
||||||
|
className="relative overflow-hidden px-8 md:px-14"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute -right-32 -top-24 h-[24rem] w-[24rem] rounded-full blur-[110px]"
|
||||||
|
style={{ background: "rgba(59,130,246,0.12)" }}
|
||||||
|
/>
|
||||||
|
<div className="relative 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: "var(--foreground)" }}
|
||||||
|
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: "var(--muted-foreground)" }}
|
||||||
|
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: "relative",
|
||||||
|
borderRadius: 28,
|
||||||
|
overflow: "hidden",
|
||||||
|
border: "1px solid var(--border)",
|
||||||
|
boxShadow: "0 24px 60px -16px rgba(0,0,0,0.25)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={TEAM_IMAGE}
|
||||||
|
alt="Equipo Rynext Technologies"
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
aspectRatio: "4/3",
|
||||||
|
objectFit: "cover",
|
||||||
|
display: "block",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Valores */}
|
||||||
|
<section
|
||||||
|
style={{ background: "var(--background)" }}
|
||||||
|
className="px-8 pb-24 md:px-14 md:pb-28"
|
||||||
|
>
|
||||||
|
<div className="mx-auto max-w-7xl">
|
||||||
|
<motion.h2
|
||||||
|
className="text-headline mb-16"
|
||||||
|
style={{ color: "var(--foreground)" }}
|
||||||
|
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-5 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
{valores.map((v, i) => {
|
||||||
|
const iconName = VALOR_ICONS[i % VALOR_ICONS.length];
|
||||||
|
return (
|
||||||
|
<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],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
whileHover={{ y: -3 }}
|
||||||
|
className="transition-shadow duration-200 hover:shadow-md"
|
||||||
|
style={{
|
||||||
|
background: "var(--card)",
|
||||||
|
border: "1px solid var(--border)",
|
||||||
|
borderRadius: 20,
|
||||||
|
padding: 28,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="mb-5 flex items-center justify-between">
|
||||||
|
<span
|
||||||
|
className="flex h-11 w-11 items-center justify-center rounded-xl"
|
||||||
|
style={{
|
||||||
|
background: "rgba(59,130,246,0.1)",
|
||||||
|
color: "#3b82f6",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon icon={iconName} width={20} />
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="font-mono text-xs font-semibold"
|
||||||
|
style={{
|
||||||
|
color: "var(--muted-foreground)",
|
||||||
|
letterSpacing: "0.06em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{v.num}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h3
|
||||||
|
className="font-display font-bold text-base mb-2.5"
|
||||||
|
style={{ color: "var(--foreground)" }}
|
||||||
|
>
|
||||||
|
{v.titulo}
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
className="text-sm leading-relaxed"
|
||||||
|
style={{ color: "var(--muted-foreground)" }}
|
||||||
|
>
|
||||||
|
{v.desc}
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Equipo */}
|
||||||
|
<section
|
||||||
|
style={{ background: "var(--background)" }}
|
||||||
|
className="px-8 pb-24 md:px-14 md:pb-28"
|
||||||
|
>
|
||||||
|
<div className="mx-auto max-w-7xl">
|
||||||
|
<motion.h2
|
||||||
|
className="text-headline mb-16"
|
||||||
|
style={{ color: "var(--foreground)" }}
|
||||||
|
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: "var(--muted-foreground)" }}>
|
||||||
|
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: "var(--muted-foreground)" }}
|
||||||
|
>
|
||||||
|
{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: "var(--border)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Horizontal branch */}
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: 0,
|
||||||
|
top: 24,
|
||||||
|
width: 16,
|
||||||
|
height: 1,
|
||||||
|
background: "var(--border)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<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],
|
||||||
|
}}
|
||||||
|
whileHover={{ y: -2 }}
|
||||||
|
className="transition-shadow duration-200 hover:shadow-md"
|
||||||
|
style={{
|
||||||
|
background: "var(--card)",
|
||||||
|
border: "1px solid var(--border)",
|
||||||
|
borderRadius: 14,
|
||||||
|
padding: "20px",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 14,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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: "var(--foreground)",
|
||||||
|
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: "var(--muted-foreground)" }}
|
||||||
|
>
|
||||||
|
{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 />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import Loader from '@/app/(landing)/components/Loader';
|
||||||
|
|
||||||
|
export default function Loading() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-dvh items-center justify-center" style={{ background: 'var(--background)' }}>
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -0,0 +1,40 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { apiFetch } from '@/app/(landing)/services/api';
|
||||||
|
|
||||||
|
export interface TeamMember {
|
||||||
|
id: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
positionName?: string;
|
||||||
|
departmentName?: string;
|
||||||
|
departmentOrder?: number;
|
||||||
|
positionOrder?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Department {
|
||||||
|
name: string;
|
||||||
|
order: number;
|
||||||
|
members: TeamMember[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTeam() {
|
||||||
|
return useQuery<TeamMember[]>({
|
||||||
|
queryKey: ["team"],
|
||||||
|
queryFn: () => apiFetch<TeamMember[]>("/api/employees/public"),
|
||||||
|
staleTime: 1000 * 60 * 5,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function groupByDepartment(members: TeamMember[]): Department[] {
|
||||||
|
const map = new Map<string, Department>();
|
||||||
|
|
||||||
|
for (const m of members) {
|
||||||
|
const key = m.departmentName ?? "Sin departamento";
|
||||||
|
if (!map.has(key)) {
|
||||||
|
map.set(key, { name: key, order: m.departmentOrder ?? 99, members: [] });
|
||||||
|
}
|
||||||
|
map.get(key)!.members.push(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(map.values()).sort((a, b) => a.order - b.order);
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -1,5 +1,3 @@
|
|||||||
import type React from 'react';
|
|
||||||
|
|
||||||
export interface ThemeProps {
|
export interface ThemeProps {
|
||||||
isNavyBg: boolean;
|
isNavyBg: boolean;
|
||||||
}
|
}
|
||||||
@@ -22,7 +20,7 @@ export interface ServiceItem {
|
|||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
features: string[];
|
features: string[];
|
||||||
icon: React.ElementType;
|
icon: string;
|
||||||
accent: 'blue' | 'red';
|
accent: 'blue' | 'red';
|
||||||
gridCols: string;
|
gridCols: string;
|
||||||
}
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
'use client';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import { ArrowLeft } from 'lucide-react';
|
|
||||||
|
|
||||||
export function NotFoundPage() {
|
|
||||||
useEffect(() => {
|
|
||||||
document.title = '404 — Página no encontrada | Rynext Technologies';
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<main
|
|
||||||
id="main-content"
|
|
||||||
className="flex min-h-screen flex-col items-center justify-center px-8 text-center"
|
|
||||||
style={{ background: '#f9f9f7' }}
|
|
||||||
>
|
|
||||||
<p
|
|
||||||
className="font-display font-black mb-6"
|
|
||||||
style={{ fontSize: 'clamp(6rem, 20vw, 12rem)', lineHeight: 1, color: '#3b82f6', letterSpacing: '-0.06em', opacity: 0.15 }}
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
404
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div style={{ marginTop: '-2rem' }}>
|
|
||||||
<h1
|
|
||||||
className="font-display font-black mb-4"
|
|
||||||
style={{ fontSize: 'clamp(1.5rem, 4vw, 2.5rem)', color: '#0a0a0a', letterSpacing: '-0.03em' }}
|
|
||||||
>
|
|
||||||
Página no encontrada.
|
|
||||||
</h1>
|
|
||||||
<p className="text-base mb-10 max-w-sm mx-auto" style={{ color: '#6a6866', lineHeight: 1.7 }}>
|
|
||||||
La página que buscas no existe o fue movida. Regresa al inicio para continuar.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<Link
|
|
||||||
href="/"
|
|
||||||
className="inline-flex items-center gap-2 px-6 py-3 text-sm font-bold text-white transition hover:opacity-90"
|
|
||||||
style={{ background: '#3b82f6', borderRadius: 6 }}
|
|
||||||
>
|
|
||||||
<ArrowLeft size={15} />
|
|
||||||
Volver al inicio
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/* Estilos propios del panel admin (Mod-Rynext).
|
||||||
|
No redefine tokens compartidos (--background, --foreground, --primary, etc.)
|
||||||
|
para no chocar con el resto de la Landing. */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--nav-bg: #001f5b;
|
||||||
|
--nav-hover: rgba(255, 255, 255, 0.08);
|
||||||
|
--nav-active: rgba(255, 255, 255, 0.15);
|
||||||
|
--nav-border: rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown animation */
|
||||||
|
@keyframes dropdown-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-6px) scale(0.97);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0) scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dropdown-out {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0) scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-6px) scale(0.97);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dropdown-in-up {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(calc(-100% + 6px)) scale(0.97);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(-100%) scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dropdown-out-up {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(-100%) scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(calc(-100% + 6px)) scale(0.97);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-dropdown {
|
||||||
|
animation: dropdown-in 0.15s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-dropdown-out {
|
||||||
|
animation: dropdown-out 0.12s ease-in forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-dropdown-up {
|
||||||
|
animation: dropdown-in-up 0.15s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-dropdown-out-up {
|
||||||
|
animation: dropdown-out-up 0.12s ease-in forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar (solo dentro del admin) */
|
||||||
|
.admin-root .scrollbar-thin::-webkit-scrollbar {
|
||||||
|
height: 6px;
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-root .scrollbar-thin::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-root .scrollbar-thin::-webkit-scrollbar-thumb {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-root .scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide number input spinners (solo dentro del admin) */
|
||||||
|
.admin-root input[type="number"]::-webkit-inner-spin-button,
|
||||||
|
.admin-root input[type="number"]::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-root input[type="number"] {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-root {
|
||||||
|
font-family: var(--font-quicksand), var(--font-dm-sans), sans-serif;
|
||||||
|
}
|
||||||
Loaded 100 of 349 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user