Componentes de layout

Los layouts son componentes que envuelven páginas completas, proporcionando una estructura consistente como encabezados, pies de página y navegación.

Layout básico

components/layout.jx
{#def title #}
{#css layout.css #}

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>{{ title }}</title>
  {{ assets.render_css() }}
  {{ assets.render_js() }}
</head>
<body>
  <header>
    <nav>
      <a href="/">Inicio</a>
      <a href="/about">Acerca de</a>
    </nav>
  </header>

  <main>
    {{ content }}
  </main>

  <footer>
    <p>&copy; 2026 Mi sitio</p>
  </footer>

</body>
</html>
components/pages/home.jx
{#import "../layout.jx" as Layout #}

<Layout title="Inicio">
  <h1>¡Bienvenido!</h1>
  <p>Esta es la página de inicio.</p>
</Layout>

Layout con slots

Usa slots con nombre para secciones personalizables:

components/layout.jx
{#def title #}

<!DOCTYPE html>
<html>
<head>
  <title>{{ title }}</title>
  {% slot head %}{% endslot %}
  {{ assets.render_css() }}
</head>
<body>
  <header>
    {% slot header %}
      <nav><a href="/">Inicio</a></nav>
    {% endslot %}
  </header>

  <main>
    {{ content }}
  </main>

  <footer>
    {% slot footer %}
      <p>&copy; 2026</p>
    {% endslot %}
  </footer>

  {% slot scripts %}{% endslot %}
  {{ assets.render_js() }}
</body>
</html>
usage
{#import "layout.jx" as Layout #}

<Layout title="Panel">
  {% fill head %}
    <meta name="robots" content="noindex">
  {% endfill %}

  {% fill header %}
    <nav>
      <a href="/dashboard">Panel</a>
      <a href="/settings">Configuración</a>
    </nav>
  {% endfill %}

  <h1>Panel</h1>
  <p>¡Bienvenido de vuelta!</p>

  {% fill scripts %}
    <script>console.log('Page loaded');</script>
  {% endfill %}
</Layout>

Layouts anidados

Crea layouts especializados que extiendan uno base:

components/layouts/base.jx
{#def title #}
{#css base.css #}

<!DOCTYPE html>
<html>
<head>
  <title>{{ title }} | Mi App</title>
  {{ assets.render_css() }}
</head>
<body>
  {{ content }}
  {{ assets.render_js() }}
</body>
</html>
components/layouts/app.jx
{#import "./base.jx" as Base #}
{#import "../sidebar.jx" as Sidebar #}
{#def title #}
{#css app.css #}

<Base title={{ title }}>
  <div class="app-layout">
    <Sidebar />
    <main class="app-content">
      {{ content }}
    </main>
  </div>
</Base>
components/layouts/auth.jx
{#import "./base.jx" as Base #}
{#def title #}
{#css auth.css #}

<Base title={{ title }}>
  <div class="auth-layout">
    <div class="auth-card">
      {{ content }}
    </div>
  </div>
</Base>
usage
{#import "layouts/app.jx" as App #}

<App title="Panel">
  <h1>Panel</h1>
</App>
usage
{#import "layouts/auth.jx" as Auth #}

<Auth title="Iniciar sesión">
  <h1>Inicia sesión</h1>
  <form>...</form>
</Auth>

Layout con resaltado de navegación

Pasa la página actual para resaltar los enlaces de navegación activos:

components/layout.jx
{#def title, current_page="" #}

<!DOCTYPE html>
<html>
<head>
  <title>{{ title }}</title>
  {{ assets.render_css() }}
</head>
<body>
  <nav>
    <a href="/" class="{{ 'active' if current_page == 'home' else '' }}">Inicio</a>
    <a href="/about" class="{{ 'active' if current_page == 'about' else '' }}">Acerca de</a>
    <a href="/contact" class="{{ 'active' if current_page == 'contact' else '' }}">Contacto</a>
  </nav>

  <main>{{ content }}</main>

  {{ assets.render_js() }}
</body>
</html>
pages/about.jx
{#import "layout.jx" as Layout #}

<Layout title="Acerca de nosotros" current_page="about">
  <h1>Acerca de nosotros</h1>
</Layout>

Secciones de layout condicionales

components/layout.jx
{#def title, show_sidebar=true, show_footer=true #}

<!DOCTYPE html>
<html>
<head>
  <title>{{ title }}</title>
  {{ assets.render_css() }}
</head>
<body>
  <div class="layout {{ 'has-sidebar' if show_sidebar else '' }}">
    {% if show_sidebar %}
      <aside class="sidebar">
        {% slot sidebar %}
          <nav>Barra lateral por defecto</nav>
        {% endslot %}
      </aside>
    {% endif %}

    <main>{{ content }}</main>
  </div>

  {% if show_footer %}
    <footer>
      {% slot footer %}<p>&copy; 2026</p>{% endslot %}
    </footer>
  {% endif %}

  {{ assets.render_js() }}
</body>
</html>
usage
{# Layout completo con barra lateral #}
<Layout title="Panel">
  {% fill sidebar %}
    <nav>Barra lateral personalizada</nav>
  {% endfill %}
  <h1>Panel</h1>
</Layout>

{# Layout mínimo sin barra lateral #}
<Layout title="Iniciar sesión" show_sidebar={{ false }} show_footer={{ false }}>
  <form>Formulario de inicio de sesión</form>
</Layout>