EmpiezaTuSaaS
Funcionalidades

Landing Pages

2 variantes de landing page con componentes listos para usar

Landing Pages

EmpiezaTuSaaS incluye 2 variantes de landing page optimizadas para conversión. Todos los componentes están en components/landing/ y se exportan desde components/landing/index.ts.

Variantes disponibles

1. Landing Page Principal (/)

La landing completa con todas las secciones. Úsala cuando tu producto ya está listo para vender.

Secciones en orden: Header → Hero → FeaturesSection → Pricing → FAQ → CTA → Footer

app/[locale]/page.tsx
import {
  Header,
  Hero,
  FeaturesSection,
  Pricing,
  FAQ,
  CTA,
  Footer,
} from "@/components/landing";

export default async function HomePage() {
  return (
    <div className="light bg-background font-kaio relative min-h-screen">
      <Header />
      <main>
        <Hero />
        <FeaturesSection />
        <Pricing />
        <FAQ />
        <CTA />
      </main>
      <Footer />
    </div>
  );
}

2. Waitlist — Lista de espera (/waitlist)

Página enfocada para validar tu idea antes de lanzar. Sin distracciones: solo logo, formulario de email y lista de beneficios.

Cuándo usarla: cuando todavía no tienes el producto listo pero quieres capturar emails de interesados.

app/[locale]/waitlist/page.tsx
import { WaitlistHero } from "@/components/landing/waitlist-hero";
import { Header } from "@/components/landing/header";
import { Footer } from "@/components/landing/footer";
import { setRequestLocale, getTranslations } from "next-intl/server";

type Props = { params: Promise<{ locale: string }> };

export async function generateMetadata({ params }: Props) {
  const { locale } = await params;
  const t = await getTranslations({ locale, namespace: "waitlist" });
  return {
    title: t("pageTitle"),
    description: t("pageDescription", { name: "Tu SaaS" }),
  };
}

export default async function WaitlistPage({ params }: Props) {
  const { locale } = await params;
  setRequestLocale(locale);

  return (
    <div className="light min-h-screen flex flex-col">
      <Header minimal />
      <main className="flex-1">
        <WaitlistHero />
      </main>
      <Footer />
    </div>
  );
}

La waitlist usa <Header minimal /> — solo muestra el logo y el selector de idioma, sin menú de navegación ni botones de CTA. Esto mantiene al usuario enfocado en el formulario.

Cómo funciona la captura de emails:

  1. El usuario escribe su email y hace click en el botón
  2. WaitlistHero hace un POST a /api/lead con { email, source: "waitlist" }
  3. La API envía un email de notificación a siteConfig.supportEmail con los datos del lead
  4. El usuario ve un mensaje de confirmación

Header: modo normal vs minimal

El componente Header acepta un prop minimal que controla qué se muestra:

PropQué muestraCuándo usarlo
<Header />Logo + navLinks + Login + CTA + menú móvilLanding principal (/)
<Header minimal />Solo logo + selector de idiomaWaitlist, páginas de captura
// Landing principal - Header completo con navegación
<Header />

// Waitlist - Header minimal, sin distracciones
<Header minimal />

API de captura de leads (/api/lead)

La waitlist usa el endpoint /api/lead para capturar emails. Cuando alguien se apunta, recibes un email de notificación:

app/api/lead/route.ts
import { NextRequest, NextResponse } from "next/server";
import { resend } from "@/lib/email";
import { siteConfig } from "@/config/site";

export async function POST(request: NextRequest) {
  const { email, name, source } = await request.json();

  if (!email) {
    return NextResponse.json(
      { message: "El email es requerido" },
      { status: 400 }
    );
  }

  // Enviar notificación al admin
  await resend.emails.send({
    from: `${siteConfig.name} <${siteConfig.noReplyEmail}>`,
    to: siteConfig.supportEmail,
    subject: `Nuevo lead: ${email}`,
    html: `
      <h2>Nuevo lead capturado</h2>
      <p><strong>Email:</strong> ${email}</p>
      <p><strong>Nombre:</strong> ${name || "No proporcionado"}</p>
      <p><strong>Fuente:</strong> ${source || "Landing page"}</p>
      <p><strong>Fecha:</strong> ${new Date().toLocaleString("es-ES")}</p>
    `,
  });

  return NextResponse.json({ success: true });
}

Para que la captura de emails funcione, necesitas tener configuradas las variables RESEND_API_KEY y los emails en config/site.ts (supportEmail y noReplyEmail).


Componentes de Landing

Todos los componentes se exportan desde components/landing/index.ts:

ComponenteArchivoDescripción
Headerheader.tsxNavegación sticky con menú móvil. Acepta prop minimal
Herohero.tsxHero principal con video demo, social proof y CTA
FeaturesSectionfeatures-section.tsxAccordion interactivo con categorías (Auth, Pagos, Email, Stack)
Pricingpricing.tsxPlanes de precio con toggle mensual/anual y CheckoutButton
FAQfaq.tsxPreguntas frecuentes con accordion colapsable
CTActa.tsxCall-to-action final con botón de compra
Footerfooter.tsxFooter con links legales y de producto
WaitlistHerowaitlist-hero.tsxHero con formulario de email para lista de espera
LanguageSwitcherlanguage-switcher.tsxBotón para cambiar entre ES/EN

Personalización

Cambiar textos

Los textos de los componentes están en los ficheros de traducción (messages/es/landing.json y messages/en/landing.json). Para la waitlist, edita messages/es/waitlist.json.

Edita config/site.ts:

config/site.ts
navLinks: [
  { label: "Características", href: "#features" },
  { label: "Precios", href: "#pricing" },
  { label: "FAQ", href: "#faq" },
],

Cambiar planes de precio

Edita config/stripe.ts. Cambia nombres, precios y features para adaptarlos a tu producto.

Cambiar FAQ

Los textos del FAQ están en messages/es/landing.json bajo la clave faq.items.


Usar la waitlist como landing principal

Si tu producto aún no está listo, puedes hacer que / muestre la waitlist en vez de la landing completa:

app/[locale]/page.tsx
import { Header, WaitlistHero, Footer } from "@/components/landing";

export default async function HomePage() {
  return (
    <div className="light min-h-screen flex flex-col">
      <Header minimal />
      <main className="flex-1">
        <WaitlistHero />
      </main>
      <Footer />
    </div>
  );
}

Cuando tu producto esté listo, cambia <WaitlistHero /> por <Hero /> y <Header minimal /> por <Header />, y añade el resto de secciones.


Eliminar la waitlist

Si no necesitas la página de waitlist:

  1. Elimina la carpeta: rm -rf app/[locale]/waitlist/
  2. Opcional — elimina los ficheros de mensajes: messages/es/waitlist.json, messages/en/waitlist.json
  3. Opcional — elimina el import en i18n/request.ts:
// Elimina esta línea si ya no usas waitlist
...(await import(`../messages/${locale}/waitlist.json`)).default,

Estructura de rutas

RutaFicheroUso
/app/[locale]/page.tsxLanding completa (Hero + Features + Pricing + FAQ + CTA)
/waitlistapp/[locale]/waitlist/page.tsxLista de espera con formulario de email

Ambas rutas están disponibles en español (/, /waitlist) e inglés (/en, /en/waitlist).

Modo claro

Las 2 landing pages fuerzan modo claro con className="light" en su div raíz. El dashboard y las páginas de autenticación respetan el tema configurado por el usuario.

SEO

La landing principal incluye JSON-LD de tipo Organization y SoftwareApplication para mejorar el SEO. Estos componentes están en components/seo/json-ld.tsx.

On this page