Files
project-afterlife/apps/web/src/components/home/TechStackSection.tsx
consultoria-as 449c02eadc
Some checks failed
Deploy Multi-VM / Deploy VM Web (push) Has been cancelled
Deploy Multi-VM / Deploy VM Auth (push) Has been cancelled
Deploy Multi-VM / Deploy Game Servers (docker-compose.fusionfall.yml, VM_FUSIONFALL_HOST, VM_FUSIONFALL_SSH_KEY, VM_FUSIONFALL_USER, fusionfall) (push) Has been cancelled
Deploy Multi-VM / Deploy Game Servers (docker-compose.maple2.yml, VM_MAPLE2_HOST, VM_MAPLE2_SSH_KEY, VM_MAPLE2_USER, maple2) (push) Has been cancelled
Deploy Multi-VM / Deploy Game Servers (docker-compose.minecraft.yml, VM_MINECRAFT_HOST, VM_MINECRAFT_SSH_KEY, VM_MINECRAFT_USER, minecraft) (push) Has been cancelled
Deploy Multi-VM / Deploy Game Servers (docker-compose.retro.yml, VM_RETRO_HOST, VM_RETRO_SSH_KEY, VM_RETRO_USER, retro) (push) Has been cancelled
feat: phase 3 redesign, game images, auth system, vm guides, service isolation
- Redesign all internal pages to warm/gold aesthetic (catalog, game detail,
  documentary, about, donate, community, guides, contact, server-status,
  login, profile, admin, not-found)
- Add real cover images for all 4 games via Strapi CMS with getImageUrl helper
- Integrate NextAuth v5 with Authentik OIDC authentication
- Add new public pages: community, guides, contact, server-status
- Add new protected pages: login, profile, admin dashboard
- Remove legacy AFC/MercadoPago system entirely
- Add Docker Compose split files for service isolation (main, auth, fusionfall, nier)
- Add OpenFusion VM deployment configs (config.vm.ini, systemd service, README-VM)
- Add NieR Reincarnation server guide and desktop client guide
- Add architecture docs for multi-VM deployment
- Add healthcheck, SSE, contact, newsletter, admin API routes
- Add reusable UI components, skeleton loaders, activity feed, bookmark system
- Update deployment and game server documentation
2026-04-28 05:15:38 +00:00

141 lines
5.7 KiB
TypeScript

"use client";
import { motion } from "framer-motion";
import { useTranslations } from "next-intl";
const columns = [
{
key: "frontend",
icon: (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M6.75 7.5l3 2.25-3 2.25m4.5 0h3m-9 8.25h13.5A2.25 2.25 0 0021 18V6a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 6v12a2.25 2.25 0 002.25 2.25z" />
</svg>
),
items: [
{ name: "Next.js 15", desc: "App Router, SSR/ISR" },
{ name: "TypeScript", desc: "Tipado seguro" },
{ name: "Tailwind CSS", desc: "Estilos utilitarios" },
{ name: "Framer Motion", desc: "Animaciones" },
{ name: "next-intl", desc: "i18n" },
{ name: "Howler.js", desc: "Audio player" },
],
},
{
key: "backend",
icon: (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z" />
</svg>
),
items: [
{ name: "Strapi 5", desc: "CMS Headless" },
{ name: "PostgreSQL", desc: "Base de datos" },
{ name: "MinIO", desc: "Almacenamiento de medios" },
],
},
{
key: "infra",
icon: (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 15a4.5 4.5 0 004.5 4.5H18a3.75 3.75 0 001.332-7.257 3 3 0 00-3.758-3.848 5.25 5.25 0 00-10.233 2.33A4.502 4.502 0 002.25 15z" />
</svg>
),
items: [
{ name: "Docker", desc: "Docker Compose" },
{ name: "Nginx", desc: "Reverse proxy" },
{ name: "Self-Hosted", desc: "100% propio" },
{ name: "CI/CD", desc: "GitHub Actions" },
],
},
];
export function TechStackSection() {
const t = useTranslations("home");
return (
<section className="py-24 px-4" style={{ background: "var(--bg-secondary)" }}>
<div className="max-w-[1200px] mx-auto">
{/* Header */}
<motion.div
className="text-center max-w-[700px] mx-auto mb-16"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-50px" }}
transition={{ duration: 0.6, ease: [0.16, 1, 0.3, 1] }}
>
<div
className="text-sm font-semibold uppercase tracking-[0.15em] mb-4"
style={{ fontFamily: "var(--font-display)", color: "var(--accent-primary)" }}
>
{t("stack_label")}
</div>
<h2
className="text-[clamp(2rem,4vw,3rem)] font-extrabold mb-4"
style={{ fontFamily: "var(--font-display)", letterSpacing: "-0.02em" }}
>
{t("stack_title")}
<span style={{ color: "var(--accent-primary)" }}>{t("stack_title_span")}</span>
</h2>
<p className="text-[1.1rem] leading-[1.7]" style={{ color: "var(--text-secondary)" }}>
{t("stack_subtitle")}
</p>
</motion.div>
{/* Grid */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{columns.map((col, colIndex) => (
<motion.div
key={col.key}
className="rounded-[20px] p-8"
style={{
background: "var(--bg-card)",
border: "1px solid var(--border-color)",
}}
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-50px" }}
transition={{ duration: 0.6, ease: [0.16, 1, 0.3, 1], delay: colIndex * 0.1 }}
>
{/* Header */}
<div className="flex items-center gap-3 mb-6">
<div
className="w-10 h-10 flex items-center justify-center rounded-lg"
style={{
background: "linear-gradient(135deg, rgba(212, 165, 116, 0.15), rgba(212, 165, 116, 0.05))",
color: "var(--accent-primary)",
}}
>
{col.icon}
</div>
<h3 className="text-lg font-bold" style={{ fontFamily: "var(--font-display)" }}>
{t(`stack_${col.key}`)}
</h3>
</div>
{/* Items */}
<div className="space-y-3">
{col.items.map((item, index) => (
<div key={index} className="flex items-center gap-3">
<div
className="w-2 h-2 rounded-full flex-shrink-0"
style={{ background: "var(--accent-primary)" }}
/>
<div className="flex-1 min-w-0">
<span className="text-sm font-medium" style={{ color: "var(--text-primary)" }}>
{item.name}
</span>
<span className="text-xs ml-2" style={{ color: "var(--text-muted)" }}>
{item.desc}
</span>
</div>
</div>
))}
</div>
</motion.div>
))}
</div>
</div>
</section>
);
}