Admin
Estado: BetaEncabezado de página
El encabezado de cada pantalla del admin: migas, título con conteo, una línea que diga qué hay aquí, la acción principal a la derecha y, debajo, las pestañas o filtros de la vista. Con sticky se queda arriba y, solo cuando el contenido ya pasa por debajo, toma fondo de vidrio y una línea.
- Admin
- Sticky
- eui-glass
- Slots
Usuarios 47
Alumnos, maestras y admins del estudio.
- Ana García ana.garcia@correo.mx
- Iván López ivan@lunaestudio.mx
- Mariana Peña mariana.pena@correo.mx
- Sofía Ruiz sofia@lunaestudio.mx
- Diego Hernández diego.hdz@correo.mx
- Lucía Torres lucia.torres@correo.mx
- Regina Castro regina@lunaestudio.mx
- Tomás Navarro tomas.navarro@correo.mx
Usuarios 47
Alumnos, maestras y admins del estudio.
- Ana García ana.garcia@correo.mx
- Iván López ivan@lunaestudio.mx
- Mariana Peña mariana.pena@correo.mx
- Sofía Ruiz sofia@lunaestudio.mx
- Diego Hernández diego.hdz@correo.mx
- Lucía Torres lucia.torres@correo.mx
- Regina Castro regina@lunaestudio.mx
- Tomás Navarro tomas.navarro@correo.mx
app/views/… (la demo de arriba)
<% people = [ [ "Ana García", "ana.garcia@correo.mx" ], [ "Iván López", "ivan@lunaestudio.mx" ], [ "Mariana Peña", "mariana.pena@correo.mx" ],
[ "Sofía Ruiz", "sofia@lunaestudio.mx" ], [ "Diego Hernández", "diego.hdz@correo.mx" ], [ "Lucía Torres", "lucia.torres@correo.mx" ],
[ "Regina Castro", "regina@lunaestudio.mx" ], [ "Tomás Navarro", "tomas.navarro@correo.mx" ] ] %>
<%# Un panel con scroll hace las veces de <main> del admin: desplázalo y el encabezado se vuelve vidrio. %>
<div class="w-full max-w-3xl">
<div class="h-80 overflow-y-auto overscroll-contain rounded-2xl border border-border bg-background px-4 pb-4 eui-focus sm:px-5" tabindex="0" role="region" aria-label="Vista previa del admin">
<%= render Ui::PageHeaderComponent.new(title: "Usuarios", count: 47, heading: :h2, sticky: true, class: "-mx-4 px-4 sm:-mx-5 sm:px-5",
description: "Alumnos, maestras y admins del estudio.",
breadcrumbs: [ [ "Panel", "#page-header-panel" ], [ "Usuarios" ] ]) do |header| %>
<% header.with_actions do %>
<%= render Ui::ButtonComponent.new(variant: :secondary, size: :sm, href: "#page-header-exportar") do %>Exportar<% end %>
<%= render Ui::ButtonComponent.new(size: :sm, href: "#page-header-nuevo") do %>
<%= render Ui::IconComponent.new(:plus, size: :sm) %>
Nuevo usuario
<% end %>
<% end %>
<% header.with_tabs do %>
<%= render Ui::SegmentedControlComponent.new(label: "Filtrar por rol", selected: "all") do |seg| %>
<% seg.with_option(label: "Todos", value: "all", count: 47, href: "#page-header-todos", data: { turbo: false }) %>
<% seg.with_option(label: "Alumnos", value: "student", count: 38, href: "#page-header-alumnos", data: { turbo: false }) %>
<% seg.with_option(label: "Maestros", value: "teacher", count: 6, href: "#page-header-maestros", data: { turbo: false }) %>
<% seg.with_option(label: "Admins", value: "admin", count: 3, href: "#page-header-admins", data: { turbo: false }) %>
<% end %>
<% end %>
<% end %>
<ul class="divide-y divide-border-subtle overflow-hidden rounded-xl border border-border bg-card">
<% people.each do |name, email| %>
<li class="flex items-center gap-3 px-4 py-3">
<span class="grid size-8 shrink-0 place-items-center rounded-full border border-border-subtle bg-raised text-2xs font-medium text-muted-foreground" aria-hidden="true"><%= name.split.map(&:first).join %></span>
<span class="min-w-0 leading-tight">
<span class="block truncate text-sm font-medium text-foreground"><%= name %></span>
<span class="mt-0.5 block truncate text-xs text-faint"><%= email %></span>
</span>
</li>
<% end %>
</ul>
</div>
</div>Qué hace
- El vidrio aparece solo cuando el encabezado ya está pegado y el contenido pasa por debajo.
- Detecta el contenedor que se desplaza (en el layout del admin es <main>), no solo la ventana.
- Las acciones bajan bajo el título en pantallas angostas sin romper el renglón.
Props
| Nombre | Tipo | Default | Descripción |
|---|---|---|---|
| title / description | String | — / nil | El nombre de la pantalla y una línea de contexto. |
| count | Integer | nil | Conteo junto al título (p. ej. @pagy.count). |
| eyebrow | String | nil | Etiqueta técnica sobre el título (eui-label). |
| breadcrumbs | Array<[label, href]> | [] | Migas; la última es la página actual (sin enlace, aria-current). |
| sticky / offset | Boolean / String (CSS) | false / "0px" | Se pega al contenedor que se desplaza; offset si hay algo más fijo encima. |
| heading | :h1…:h6 (o 1–6) | :h1 | El nivel del título según la página (heading_level: es su nombre anterior). |
| with_actions / with_tabs | slots | — | La acción principal (y secundarias) a la derecha; pestañas o filtros debajo. |
Accesibilidad
- <header> con el título como encabezado real (nivel configurable).
- Migas en un <nav aria-label="Ruta"> con lista ordenada y aria-current en la página actual.