Skip to content

Tutorial: Crear una Página

Las páginas en este proyecto son delegadores — no contienen lógica ni UI directamente. Su único trabajo es invocar el layout correcto según la vertical activa. Toda la lógica real vive en los layouts.


app/pages/webinars/index.vue → 7 líneas, solo invoca layout
app/layouts/pages/inspiria/webinars.vue → 200+ líneas, toda la lógica y UI

Esto permite que la misma ruta (/webinars) muestre una UI completamente diferente según la vertical activa, sin tocar el archivo de página.


TipoLayout enSe selecciona con
Común (login, registro, cuenta)layouts/pages/login.vuecommonLayout: true
Específica (cursos, lives, books)layouts/pages/inspiria/courses.vuecommonLayout: false

Ejemplo: Página de Webinars (específica de Inspiria)

Section titled “Ejemplo: Página de Webinars (específica de Inspiria)”
  1. Crea el archivo de página (thin page)

    Crea app/pages/webinars/index.vue:

    <script setup lang="ts">
    import { chooseLayoutPage } from '~/core/plugins'
    const layout = chooseLayoutPage({ page: 'webinars', commonLayout: false })
    </script>
    <template>
    <NuxtLayout :name="layout"></NuxtLayout>
    </template>

    Eso es todo. La página solo hace dos cosas:

    • Llama a chooseLayoutPage para resolver qué layout usar
    • Renderiza ese layout con <NuxtLayout>
  2. Crea el layout (donde vive la lógica real)

    Crea app/layouts/pages/inspiria/webinars.vue:

    <template>
    <section class="webinars-page container mx-auto px-4 py-8">
    <h1 class="text-h1 font-bold text-graphite mb-6">
    {{ pageData?.title }}
    </h1>
    <div v-if="isPending" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
    <AESkeletonLoader v-for="i in 6" :key="i" />
    </div>
    <div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
    <AEMainCard
    v-for="webinar in data"
    :key="webinar.id"
    :product="webinar"
    />
    </div>
    </section>
    </template>
    <script setup lang="ts">
    const { data: pageData } = await useLocales<{ title: string }>('webinars')
    const { data, isPending } = useServices('getWebinars')
    </script>

    El layout va en layouts/pages/inspiria/ porque es específico de la vertical Inspiria. Si fuera una página común (compartida), iría directamente en layouts/pages/.

  3. Registra la página como tipo válido

    En app/types/pages.d.ts, agrega el nombre de la página al tipo LayoutPage:

    export type LayoutPage =
    | 'courses'
    | 'lives'
    | 'books'
    | 'webinars' // ← agregar aquí
    | // ... otras páginas

    Esto permite que TypeScript valide los nombres en chooseLayoutPage y en exclusivePages.

  4. Registra en exclusivePages de la vertical

    Abre app/constants/verticals/inspiria.ts y agrega la página:

    export const INSPIRIA: InspiriaVertical = {
    // ...
    exclusivePages: ['books', 'presentials', 'courses', 'webinars'],
    }
  5. Crea las traducciones del contenido

    app/locales/inspiria/es/webinars.json
    {
    "title": "Webinars",
    "subtitle": "Formación en directo con expertos"
    }
    app/locales/inspiria/en/webinars.json
    {
    "title": "Webinars",
    "subtitle": "Live training with experts"
    }
  6. (Opcional) Registra traducciones de la ruta en i18n

    Si la URL debe traducirse entre idiomas:

    // Configuración de pages en i18n
    {
    webinars: {
    es: '/webinars',
    en: '/webinars',
    'pt-BR': '/webinars',
    },
    }

Ejemplo: Página común (compartida entre verticales)

Section titled “Ejemplo: Página común (compartida entre verticales)”

Para una página que todas las verticales comparten (login, soporte, etc.):

app/pages/support.vue
<script setup lang="ts">
import { chooseLayoutPage } from '~/core/plugins'
const layout = chooseLayoutPage({ page: 'support', commonLayout: true })
</script>
<template>
<NuxtLayout :name="layout"></NuxtLayout>
</template>

El layout va en app/layouts/pages/support.vue (sin subcarpeta de vertical).


pages/
└── webinars/
└── index.vue → thin page (7 líneas)
layouts/
└── pages/
├── support.vue → layout COMÚN (todas las verticales)
└── inspiria/
└── webinars.vue → layout ESPECÍFICO (solo Inspiria)

La magia del multi-vertical: si mañana se agrega otra vertical con su propia versión de “webinars”, solo se crea layouts/pages/otra-vertical/webinars.vue — la misma página (pages/webinars/index.vue) ya funciona sin cambios.