9aeaeafa3f
Phase 1 — Design System: - Glassmorphism tokens (--glass-bg, --glass-border, --blur-glass) - Gradient tokens (--hds-gradient-hero, --hds-gradient-section) - Motion tokens (--ease-spring, --ease-out-expo) - .glass-card component class with hover uplift + mouse-tracking glow - .noise-overlay: SVG feTurbulence texture at 0.025 opacity - Buttons with spring easing, prefers-reduced-motion support Phase 2 — Preloader + Hero: - Preloader.astro: vanilla JS logo fade-in + loading bar + slide-up - Uses sessionStorage to skip on repeat visits - Hero.astro: full-bleed 100dvh, GSAP timeline, glass ring decoration - Parallax floating SVG shapes (sine yoyo animation) - i18n: hero.scrollDown key Phase 3 — 'Por qué elegirnos' Bento Grid: - DifferenceCards.astro: asymmetric 3-column bento grid - Glass cards with mouse-tracking glow (--mouse-x/--mouse-y) - GSAP ScrollTrigger stagger reveal (opacity 0→1, y: 40→0) Phase 4 — Pricing + Process: - planes.astro: 5 visible + 4 in details accordion - Empresarial as hero card, price annual only (no toggle) - ProcessSteps.astro: timeline + ScrollTrigger progress bar Phase 5 — Global Polish: - LenisScroll.astro: smooth scroll (duration 1.2, cubic easing) - GSAP ticker sync, noise overlay in BaseLayout Phase 6 — Deploy: - deploy.sh: auto-detects repo path, auto-builds if stale - Relative paths instead of hardcoded /root/opencode/development
209 lines
11 KiB
Plaintext
209 lines
11 KiB
Plaintext
---
|
|
import BaseLayout from '@/layouts/BaseLayout.astro';
|
|
import SectionEyebrow from '@/components/SectionEyebrow.astro';
|
|
import PricingTiersFeatured from '@/components/PricingTiersFeatured.astro';
|
|
import CloudDivider from '@/components/CloudDivider.astro';
|
|
import CtaFinal from '@/components/CtaFinal.astro';
|
|
import { PLANS } from '@/lib/pricing';
|
|
import { getLangFromUrl, useTranslations } from '@/i18n/utils';
|
|
|
|
const lang = getLangFromUrl(Astro.url);
|
|
const t = useTranslations(lang);
|
|
const whatsappUrl = 'https://wa.me/59899812487';
|
|
const base = lang === 'en' ? '/en' : '';
|
|
|
|
// 5 visible plans on home — Empresarial as hero
|
|
const VISIBLE_SLUGS = ['basico', 'institucional', 'empresarial', 'e-commerce', 'avanzado'];
|
|
const visible = PLANS.filter(p => VISIBLE_SLUGS.includes(p.slug));
|
|
const empresarial = PLANS.find(p => p.slug === 'empresarial');
|
|
const visibleWithoutHero = visible.filter(p => p.slug !== 'empresarial');
|
|
const advanced = PLANS.filter(p => !VISIBLE_SLUGS.includes(p.slug));
|
|
|
|
function monthly(annual: number): string {
|
|
return (annual / 12).toFixed(2);
|
|
}
|
|
---
|
|
<BaseLayout
|
|
title={lang === 'en' ? 'Hosting plans' : 'Planes de hosting'}
|
|
description={lang === 'en'
|
|
? 'Hosting plans in USD, billed annually. From basic to corporate HD, choose the plan that fits your project.'
|
|
: 'Planes de hosting en USD, con cobro anual. Desde básico hasta corporativo HD, elegí el plan que se adapta a tu proyecto.'}
|
|
lang={lang}
|
|
>
|
|
<section class="pt-24 pb-16 md:pt-32 md:pb-20 relative overflow-hidden" style="background: var(--hds-bg-soft);">
|
|
<div class="absolute inset-0" style="background: var(--hds-gradient-hero);" aria-hidden="true"></div>
|
|
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
|
<SectionEyebrow text={lang === 'en' ? 'Hosting plans' : 'Planes de hosting'} />
|
|
<h1 class="font-display leading-tight mt-5" style="font-size: clamp(2.5rem, 6vw, 4.5rem); color: var(--hds-fg);">
|
|
{lang === 'en' ? 'Plans designed around your' : 'Planes pensados alrededor de tu'} <span style="color: var(--color-hds-naranja);">{lang === 'en' ? 'project' : 'proyecto'}</span>.
|
|
</h1>
|
|
<p class="text-lg mt-5 max-w-2xl mx-auto" style="color: var(--hds-fg-soft);">
|
|
{lang === 'en'
|
|
? 'Prices in USD, billed annually. No surprises, no hidden costs.'
|
|
: 'Precios en USD, facturación anual. Sin sorpresas, sin costos ocultos.'}
|
|
</p>
|
|
</div>
|
|
</section>
|
|
|
|
<CloudDivider fillClass="fill-hds-bg" />
|
|
|
|
<!-- Hero plan: Empresarial (glass-card-hero) -->
|
|
{empresarial && (
|
|
<section class="py-16 md:py-24" style="background: var(--hds-bg);">
|
|
<div class="max-w-xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="text-center mb-8">
|
|
<span class="inline-block px-3 py-1 rounded-full text-xs font-semibold tracking-[0.2em] uppercase mb-4" style="background: var(--hds-bg-soft); color: var(--color-hds-naranja);">
|
|
{lang === 'en' ? 'Most popular' : 'El más elegido'}
|
|
</span>
|
|
</div>
|
|
|
|
<article class="glass-card glass-card-hero p-8 md:p-12 text-center">
|
|
<div class="text-xs font-semibold tracking-[0.25em] uppercase mb-3" style="color: var(--color-hds-naranja);">
|
|
{empresarial.name}
|
|
</div>
|
|
<div class="flex items-baseline justify-center gap-1.5 mb-6">
|
|
<span class="text-lg font-semibold" style="color: var(--hds-fg-soft);">US$</span>
|
|
<span class="font-display leading-none" style="font-size: 5rem; color: var(--hds-fg); font-weight: 500; letter-spacing: -0.03em;">{empresarial.priceUsdYear}</span>
|
|
<span class="text-lg" style="color: var(--hds-fg-soft);">/año</span>
|
|
</div>
|
|
<div class="text-sm mb-8" style="color: var(--hds-fg-muted);">
|
|
(US${monthly(empresarial.priceUsdYear)}/mes)
|
|
</div>
|
|
|
|
<div class="border-t pt-6 mb-8" style="border-color: var(--glass-border);">
|
|
<ul class="grid grid-cols-2 gap-2.5 text-sm text-left max-w-md mx-auto">
|
|
{empresarial.features.map(f => (
|
|
<li class="flex items-start gap-2.5">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="flex-shrink-0 mt-0.5" style="color: var(--color-hds-naranja);" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg>
|
|
<span style="color: var(--hds-fg-soft);">{f}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
<a href={whatsappUrl} target="_blank" rel="noopener noreferrer" class="btn-primary text-base px-10 inline-flex">
|
|
{lang === 'en' ? 'Choose' : 'Elegir'} {empresarial.name}
|
|
</a>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
)}
|
|
|
|
<!-- 4 secondary plans (glass cards in 2-col grid) -->
|
|
<section class="py-12 md:py-16" style="background: var(--hds-bg);">
|
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="text-center mb-10">
|
|
<h2 class="font-display" style="font-size: clamp(1.5rem, 3.5vw, 2.25rem); color: var(--hds-fg);">
|
|
{lang === 'en' ? 'More options for every need' : 'Más opciones para cada necesidad'}
|
|
</h2>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 stagger">
|
|
{visibleWithoutHero.map(plan => (
|
|
<article class="glass-card p-8 flex flex-col h-full">
|
|
<div class="text-xs font-semibold tracking-[0.25em] uppercase mb-3" style={`color: ${plan.slug === 'institucional' ? 'var(--color-hds-naranja)' : 'var(--hds-fg-muted)'};`}>
|
|
{plan.slug === 'institucional' ? `⭐ ${plan.name} (recomendado)` : plan.name}
|
|
</div>
|
|
<div class="flex items-baseline gap-1 mb-3">
|
|
<span class="text-lg font-semibold" style="color: var(--hds-fg-soft);">US$</span>
|
|
<span class="font-display leading-none" style="font-size: 3.5rem; color: var(--hds-fg); font-weight: 500; letter-spacing: -0.03em;">{plan.priceUsdYear}</span>
|
|
<span class="text-sm" style="color: var(--hds-fg-soft);">/año</span>
|
|
</div>
|
|
<div class="text-xs mb-6" style="color: var(--hds-fg-muted);">
|
|
(US${monthly(plan.priceUsdYear)}/mes)
|
|
</div>
|
|
|
|
<div class="border-t pt-5 mb-6 flex-grow" style="border-color: var(--glass-border);">
|
|
<ul class="space-y-2 text-sm">
|
|
{plan.features.slice(0, 5).map(f => (
|
|
<li class="flex items-start gap-2.5">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="flex-shrink-0 mt-0.5" style="color: var(--color-hds-naranja);" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg>
|
|
<span style="color: var(--hds-fg-soft);">{f}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
{plan.features.length > 5 && (
|
|
<p class="text-xs mt-3 italic" style="color: var(--hds-fg-muted);">
|
|
+{plan.features.length - 5} características más
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<a href={whatsappUrl} target="_blank" rel="noopener noreferrer" class="btn-secondary justify-center">
|
|
{lang === 'en' ? 'Choose' : 'Elegir'} {plan.name}
|
|
</a>
|
|
</article>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Advanced plans accordion -->
|
|
<section class="py-12 md:py-20" style="background: var(--hds-bg);">
|
|
<div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<details class="group">
|
|
<summary class="flex items-center justify-between cursor-pointer py-4 px-6 rounded-2xl glass-card">
|
|
<div>
|
|
<span class="font-semibold" style="color: var(--hds-fg);">
|
|
{lang === 'en' ? 'Advanced plans' : 'Planes avanzados'}
|
|
</span>
|
|
<span class="text-sm ml-3" style="color: var(--hds-fg-muted);">
|
|
{lang === 'en' ? `${advanced.length} plans for high-demand projects` : `${advanced.length} planes para proyectos de alta demanda`}
|
|
</span>
|
|
</div>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="transition-transform group-open:rotate-180" style="color: var(--color-hds-naranja);" aria-hidden="true">
|
|
<polyline points="6 9 12 15 18 9"/>
|
|
</svg>
|
|
</summary>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-5 mt-6">
|
|
{advanced.map(plan => (
|
|
<article class="glass-card p-6 flex flex-col h-full">
|
|
<div class="text-xs font-semibold tracking-[0.2em] uppercase mb-3" style="color: var(--hds-fg-muted);">
|
|
{plan.name}
|
|
</div>
|
|
<div class="flex items-baseline gap-1 mb-2">
|
|
<span class="text-sm font-semibold" style="color: var(--hds-fg-soft);">US$</span>
|
|
<span class="font-display leading-none" style="font-size: 2.75rem; color: var(--hds-fg); font-weight: 500; letter-spacing: -0.03em;">{plan.priceUsdYear}</span>
|
|
<span class="text-xs" style="color: var(--hds-fg-soft);">/año</span>
|
|
</div>
|
|
<div class="text-xs mb-4" style="color: var(--hds-fg-muted);">
|
|
(US${monthly(plan.priceUsdYear)}/mes)
|
|
</div>
|
|
|
|
<div class="border-t pt-4 mb-5 flex-grow" style="border-color: var(--glass-border);">
|
|
<ul class="space-y-1.5 text-sm">
|
|
{plan.features.slice(0, 5).map(f => (
|
|
<li class="flex items-start gap-2.5">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="flex-shrink-0 mt-0.5" style="color: var(--color-hds-naranja);" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg>
|
|
<span style="color: var(--hds-fg-soft);">{f}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
<a href={whatsappUrl} target="_blank" rel="noopener noreferrer" class="btn-ghost justify-center text-sm">
|
|
{lang === 'en' ? 'Choose' : 'Elegir'} {plan.name}
|
|
</a>
|
|
</article>
|
|
))}
|
|
</div>
|
|
</details>
|
|
</div>
|
|
</section>
|
|
|
|
<CloudDivider fillClass="fill-hds-bg-soft" />
|
|
|
|
<!-- CTA -->
|
|
<section class="py-16 md:py-24" style="background: var(--hds-bg-soft);">
|
|
<div class="max-w-2xl mx-auto px-4 text-center">
|
|
<p class="text-sm mb-4" style="color: var(--hds-fg-muted);">
|
|
{lang === 'en' ? 'Need a custom plan?' : '¿Necesitás un plan a medida?'}
|
|
</p>
|
|
<a href={whatsappUrl} target="_blank" rel="noopener noreferrer" class="btn-primary text-base px-10 inline-flex">
|
|
{lang === 'en' ? 'Let us talk' : 'Charlemos'}
|
|
</a>
|
|
</div>
|
|
</section>
|
|
</BaseLayout>
|