Ir al contenido
Secciones
Idioma, actualmente Español
Sistema de diseño Rastrillo

Pantalla de lista

Pantalla de lista genérica con título, barra de herramientas y filas que funcionan en escritorio y en móvil.

Cada ejemplo funciona de verdad, pero sus enlaces no llevan a ninguna parte. HTML muestra el marcado para copiar.

page-header

La barra de título de la pantalla: un h1, un subtítulo opcional y una acción principal.

Título, subtítulo y una acción principal

Vista previa
<header rst-page-header>
  <div rst-page-header-titles>
    <h1>Entradas</h1>
    <p rst-page-header-sub>Todo lo que has escrito, lo más reciente primero.</p>
  </div>
  <a rst-btn="primary" href="/posts/new">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
    Escribir una entrada
  </a>
</header>
{{template "page-header" dict
    "Title" "Entradas"
    "Sub" "Todo lo que has escrito, lo más reciente primero."
    "ActionHref" "/posts/new"
    "ActionLabel" "Escribir una entrada"
    "ActionIcon" "plus"}}

Solo el título

Vista previa
<header rst-page-header>
  <div rst-page-header-titles>
    <h1>Ajustes</h1>
  </div>
</header>
{{template "page-header" dict "Title" "Ajustes"}}

list-bar

La barra de herramientas en la parte superior de una tarjeta de lista, con búsqueda y filtro.

Búsqueda con un desplegable de filtro

Vista previa

Pon esto dentro de <div rst-list>.

<div rst-lbar>
  <search>
    <form rst-search method="get" action="/posts">
      <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
      <input type="search" name="q" value="versión" placeholder="Buscar entradas" aria-label="Buscar entradas">
      <a rst-search-clear href="/posts?sort=newest" aria-label="Borrar la búsqueda">
        <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
      </a>
      <input type="hidden" name="sort" value="newest">
      <button class="rst-sr-only" type="submit">Buscar</button>
    </form>
  </search>
  <details rst-dropdown name="rst-menus">
    <summary rst-btn aria-label="Filtrar por estado: Pagado">
      Pagado
      <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>
    </summary>
    <div rst-dropdown-menu>
      <a href="/posts">Todo</a>
      <a href="/posts?status=paid" aria-current="true">Pagado <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></a>
      <a href="/posts?status=free">Gratis</a>
    </div>
  </details>
</div>

Pon esto dentro de <div rst-list>.

{{template "list-bar" dict
    "Filter" (dict "Aria" "Filtrar por estado: Pagado" "Items" (list (dict "Href" "/posts" "Label" "Todo") (dict "Current" true "Href" "/posts?status=paid" "Label" "Pagado") (dict "Href" "/posts?status=free" "Label" "Gratis")) "Label" "Pagado")
    "Hidden" (list (list "sort" "newest"))
    "Placeholder" "Buscar entradas"
    "Query" "versión"
    "SearchAction" "/posts"}}

list-search-submit

El botón de enviar de verdad del formulario de búsqueda: oculto a la vista, dentro del orden de tabulación, y aparece al recibir el foco del teclado.

Etiqueta por defecto

Vista previa

Pon esto dentro de <section rst-box>.

<button class="rst-sr-only" type="submit">Buscar</button>

Pon esto dentro de <section rst-box>.

{{template "list-search-submit" dict}}

Aquí no se ve nada hasta que llegas con el tabulador.

list-row-action

Una fila de lista: el nombre del registro como enlace principal, una línea de datos y una acción secundaria.

Marca inicial, estado y una acción

Vista previa

Pon esto dentro de <div rst-list>.

<div rst-row>
  <span rst-row-lead data-lead="accent" aria-hidden="true">RN</span>
  <span rst-row-main><a href="/posts/1">Notas de la versión, agosto</a>
    <small rst-row-sub>Publicado el 2 de agosto · 4 min de lectura</small>
  </span>
  <span rst-status rst-tone="positive">Publicado</span>
  <a rst-row-action href="/posts/1/edit" aria-label="Editar Notas de la versión, agosto">Editar</a>
</div>

Pon esto dentro de <div rst-list>.

{{template "list-row-action" dict
    "Href" "/posts/1"
    "Main" "Notas de la versión, agosto"
    "Sub" "Publicado el 2 de agosto · 4 min de lectura"
    "ActionHref" "/posts/1/edit"
    "ActionLabel" "Editar"
    "ActionAria" "Editar Notas de la versión, agosto"
    "StatusTone" "positive"
    "StatusLabel" "Publicado"
    "Lead" "accent"
    "LeadInitial" "RN"}}

Solo el nombre y la línea de detalle

Vista previa

Pon esto dentro de <div rst-list>.

<div rst-row>
  <span rst-row-main><a href="/posts/2">Por qué dejamos el antiguo ejecutor</a>
    <small rst-row-sub>Borrador · guardado hace 20 minutos</small>
  </span>
</div>

Pon esto dentro de <div rst-list>.

{{template "list-row-action" dict
    "Href" "/posts/2"
    "Main" "Por qué dejamos el antiguo ejecutor"
    "Sub" "Borrador · guardado hace 20 minutos"}}

row-menu

Las demás acciones de una fila, tras un botón ⋮. Una destructiva enlaza a su página de confirmación.

Enlaces, un formulario y un elemento destructivo

Vista previa
<details rst-row-menu name="rst-menus">
  <summary aria-label="Acciones para Grace Hopper">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>
  </summary>
  <div rst-row-menu-panel>
    <a href="/orders/AB3PX/edit">Editar</a>
    <form method="post" action="/orders/AB3PX/archive">
      <input type="hidden" name="state" value="archived">
      <button type="submit">Archivar</button>
    </form>
    <hr>
    <a class="rst-danger" href="/orders/AB3PX/delete">Eliminar pedido…</a>
  </div>
</details>
{{template "row-menu" dict
    "Name" "Grace Hopper"
    "Items" (list
        (dict "Href" "/orders/AB3PX/edit" "Label" "Editar")
        (dict "Action" "/orders/AB3PX/archive" "Hidden" (list (list "state" "archived")) "Label" "Archivar")
        (dict "Danger" true "Href" "/orders/AB3PX/delete" "Label" "Eliminar pedido…"))}}

Pon el elemento destructivo al final y termina su etiqueta con …. Abre una página que pregunta antes de borrar nada.

Solo enlaces, para una lista dentro de un formulario de selección

Vista previa
<details rst-row-menu name="rst-menus">
  <summary aria-label="Acciones para Alan Turing">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>
  </summary>
  <div rst-row-menu-panel>
    <a href="/orders/CD4QY/edit">Editar</a>
    <hr>
    <a class="rst-danger" href="/orders/CD4QY/delete">Eliminar pedido…</a>
  </div>
</details>
{{template "row-menu" dict
    "Name" "Alan Turing"
    "Items" (list
        (dict "Href" "/orders/CD4QY/edit" "Label" "Editar")
        (dict "Danger" true "Href" "/orders/CD4QY/delete" "Label" "Eliminar pedido…"))}}

Dentro de un formulario, cada elemento debe ser un enlace. Una acción que envía datos pasa por una página propia.

seg-tabs

Un control segmentado de enlaces renderizados en el servidor. La pestaña actual es aria-current en un enlace.

Dos secciones

Vista previa
<nav rst-seg-tabs aria-label="Secciones de la entrada">
  <a href="?tab=basics" aria-current="page">Básico</a>
  <a href="?tab=advanced">Avanzado</a>
</nav>
{{template "seg-tabs" dict
    "Label" "Secciones de la entrada"
    "Items" (list
        (dict "Current" true "Href" "?tab=basics" "Label" "Básico")
        (dict "Href" "?tab=advanced" "Label" "Avanzado"))}}

dropdown

Un desplegable sin nada de JavaScript: un botón summary sobre un panel de enlaces normales.

Un menú de filtro con una opción aplicada

Vista previa
<details rst-dropdown name="rst-menus">
  <summary rst-btn aria-label="Ordenar entradas: lo más reciente primero">
    Más recientes
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>
  </summary>
  <div rst-dropdown-menu>
    <a href="/posts?sort=newest" aria-current="true">Más recientes <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></a>
    <a href="/posts?sort=oldest">Más antiguas</a>
    <a href="/posts?sort=title">Por título</a>
  </div>
</details>
{{template "dropdown" dict
    "Label" "Más recientes"
    "Aria" "Ordenar entradas: lo más reciente primero"
    "Items" (list
        (dict "Current" true "Href" "/posts?sort=newest" "Label" "Más recientes")
        (dict "Href" "/posts?sort=oldest" "Label" "Más antiguas")
        (dict "Href" "/posts?sort=title" "Label" "Por título"))}}

bulk-bar

La franja de cabecera del modo selección, que sustituye a la barra de lista: el recuento, un enlace para ampliar la selección y el menú de acciones.

Tres filas seleccionadas

Vista previa

Pon esto dentro de <div rst-list>.

<div rst-bulkbar>
  <a rst-bulkbar-close href="/posts" aria-label="Selección terminada">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
  </a>
  <span rst-bulkbar-selection><span rst-bulkbar-count>3 seleccionadas</span><a rst-bulkbar-escalate href="/posts?select=all">Seleccionar las 412 coincidencias</a></span>
  <details rst-dropdown name="rst-menus">
    <summary>
      Acciones
      <span rst-caret aria-hidden="true">
        <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>
      </span>
    </summary>
    <div rst-dropdown-menu>
      <button type="submit" name="action" value="export">Exportar</button>
      <button type="submit" name="action" value="unpublish">Retirar la publicación</button>
      <button type="submit" name="action" value="delete" class="rst-danger">Eliminar…</button>
    </div>
  </details>
</div>

Pon esto dentro de <div rst-list>.

{{template "bulk-bar" dict
    "DoneHref" "/posts"
    "Count" "3 seleccionadas"
    "EscalateHref" "/posts?select=all"
    "EscalateLabel" "Seleccionar las 412 coincidencias"
    "Actions" (list
        (dict "Label" "Exportar" "Value" "export")
        (dict "Label" "Retirar la publicación" "Value" "unpublish")
        (dict "Danger" true "Label" "Eliminar…" "Value" "delete"))
    "MenuLabel" "Acciones"}}

El elemento destructivo va al final: la primera entrada es el valor por defecto que dispara Enter en el formulario que lo rodea.

media-grid

Una cuadrícula de mosaicos de imagen. Cada marco es 4:3, así que las capturas altas y los banners anchos caben en una misma cuadrícula uniforme.

Capturas, un logotipo y un banner

Vista previa

Pon esto dentro de <div rst-list>.

<div rst-media>
  <div rst-media-tile>
    <div rst-media-frame>
      <img src="/images/checkout.png" alt="" loading="lazy" decoding="async" width="1280" height="3200">
    </div>
    <div rst-media-caption>
      <div rst-media-name>
        <a href="/images/1">Pago, paso 2</a>
        <details rst-row-menu name="rst-menus">
          <summary aria-label="Acciones para Pago, paso 2">
            <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>
          </summary>
          <div rst-row-menu-panel>
            <a href="/images/1/edit">Editar</a>
            <hr>
            <a class="rst-danger" href="/images/1/delete">Eliminar…</a>
          </div>
        </details>
      </div>
      <p rst-media-desc>El paso de pago, con el formulario de la tarjeta abierto.</p>
      <p rst-media-meta>1280 × 3200 · 412 KB</p>
    </div>
  </div>
  <div rst-media-tile>
    <div rst-media-frame>
      <img src="/images/pricing.png" alt="" loading="lazy" decoding="async" width="1280" height="2400">
    </div>
    <div rst-media-caption>
      <div rst-media-name>
        <a href="/images/2">Página de precios</a>
        <details rst-row-menu name="rst-menus">
          <summary aria-label="Acciones para Página de precios">
            <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>
          </summary>
          <div rst-row-menu-panel>
            <a href="/images/2/edit">Editar</a>
            <hr>
            <a class="rst-danger" href="/images/2/delete">Eliminar…</a>
          </div>
        </details>
      </div>
      <p rst-media-desc="none">Sin descripción</p>
      <p rst-media-meta>1280 × 2400 · 318 KB</p>
    </div>
  </div>
  <div rst-media-tile>
    <div rst-media-frame="contain">
      <img src="/images/logo.svg" alt="Harbour" loading="lazy" decoding="async" width="240" height="240">
    </div>
    <div rst-media-caption>
      <div rst-media-name>
        <a href="/images/3">Logotipo de Harbour</a>
        <details rst-row-menu name="rst-menus">
          <summary aria-label="Acciones para Logotipo de Harbour">
            <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>
          </summary>
          <div rst-row-menu-panel>
            <a href="/images/3/edit">Editar</a>
            <hr>
            <a class="rst-danger" href="/images/3/delete">Eliminar…</a>
          </div>
        </details>
      </div>
      <p rst-media-desc>La marca sola, para fondos oscuros y claros.</p>
      <p rst-media-meta>240 × 240 · 3 KB</p>
    </div>
  </div>
  <div rst-media-tile>
    <div rst-media-frame="contain">
      <img src="/images/banner.png" alt="" loading="lazy" decoding="async" width="1200" height="200">
    </div>
    <div rst-media-caption>
      <div rst-media-name>
        <a href="/images/4">Banner de primavera</a>
        <details rst-row-menu name="rst-menus">
          <summary aria-label="Acciones para Banner de primavera">
            <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>
          </summary>
          <div rst-row-menu-panel>
            <a href="/images/4/edit">Editar</a>
            <hr>
            <a class="rst-danger" href="/images/4/delete">Eliminar…</a>
          </div>
        </details>
      </div>
      <p rst-media-desc>La franja de arriba de la tienda en marzo.</p>
      <p rst-media-meta>1200 × 200 · 64 KB</p>
    </div>
  </div>
</div>

Pon esto dentro de <div rst-list>.

{{template "media-grid" dict
    "Items" (list
        (dict "Desc" "El paso de pago, con el formulario de la tarjeta abierto." "Height" 3200 "Href" "/images/1" "Menu" (list (dict "Href" "/images/1/edit" "Label" "Editar") (dict "Danger" true "Href" "/images/1/delete" "Label" "Eliminar…")) "Meta" "1280 × 3200 · 412 KB" "Name" "Pago, paso 2" "Src" "/images/checkout.png" "Width" 1280)
        (dict "Desc" "" "Height" 2400 "Href" "/images/2" "Menu" (list (dict "Href" "/images/2/edit" "Label" "Editar") (dict "Danger" true "Href" "/images/2/delete" "Label" "Eliminar…")) "Meta" "1280 × 2400 · 318 KB" "Name" "Página de precios" "Src" "/images/pricing.png" "Width" 1280)
        (dict "Alt" "Harbour" "Desc" "La marca sola, para fondos oscuros y claros." "Fit" "contain" "Height" 240 "Href" "/images/3" "Menu" (list (dict "Href" "/images/3/edit" "Label" "Editar") (dict "Danger" true "Href" "/images/3/delete" "Label" "Eliminar…")) "Meta" "240 × 240 · 3 KB" "Name" "Logotipo de Harbour" "Src" "/images/logo.svg" "Width" 240)
        (dict "Desc" "La franja de arriba de la tienda en marzo." "Fit" "contain" "Height" 200 "Href" "/images/4" "Menu" (list (dict "Href" "/images/4/edit" "Label" "Editar") (dict "Danger" true "Href" "/images/4/delete" "Label" "Eliminar…")) "Meta" "1200 × 200 · 64 KB" "Name" "Banner de primavera" "Src" "/images/banner.png" "Width" 1200))}}

Pon Fit en "contain" para un logotipo o un banner. Una captura mantiene el valor por defecto y muestra su parte superior. Un mosaico sin Desc dice "Sin descripción".

Modo de selección, un mosaico seleccionado

Vista previa

Pon esto dentro de <div rst-list>.

<div rst-media>
  <div rst-media-tile>
    <div rst-media-frame>
      <img src="/images/checkout.png" alt="" loading="lazy" decoding="async" width="1280" height="3200">
      <label rst-selbox>
        <input type="checkbox" name="id" value="1" checked aria-label="Seleccionar Pago, paso 2">
      </label>
    </div>
    <div rst-media-caption>
      <div rst-media-name>
        <a href="/images/1">Pago, paso 2</a>
        <details rst-row-menu name="rst-menus">
          <summary aria-label="Acciones para Pago, paso 2">
            <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>
          </summary>
          <div rst-row-menu-panel>
            <a href="/images/1/edit">Editar</a>
            <hr>
            <a class="rst-danger" href="/images/1/delete">Eliminar…</a>
          </div>
        </details>
      </div>
      <p rst-media-desc>El paso de pago, con el formulario de la tarjeta abierto.</p>
      <p rst-media-meta>1280 × 3200 · 412 KB</p>
    </div>
  </div>
  <div rst-media-tile>
    <div rst-media-frame>
      <img src="/images/pricing.png" alt="" loading="lazy" decoding="async" width="1280" height="2400">
      <label rst-selbox>
        <input type="checkbox" name="id" value="2" aria-label="Seleccionar Página de precios">
      </label>
    </div>
    <div rst-media-caption>
      <div rst-media-name>
        <a href="/images/2">Página de precios</a>
        <details rst-row-menu name="rst-menus">
          <summary aria-label="Acciones para Página de precios">
            <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>
          </summary>
          <div rst-row-menu-panel>
            <a href="/images/2/edit">Editar</a>
            <hr>
            <a class="rst-danger" href="/images/2/delete">Eliminar…</a>
          </div>
        </details>
      </div>
      <p rst-media-desc="none">Sin descripción</p>
      <p rst-media-meta>1280 × 2400 · 318 KB</p>
    </div>
  </div>
</div>

Pon esto dentro de <div rst-list>.

{{template "media-grid" dict
    "Items" (list
        (dict "Desc" "El paso de pago, con el formulario de la tarjeta abierto." "Height" 3200 "Href" "/images/1" "Menu" (list (dict "Href" "/images/1/edit" "Label" "Editar") (dict "Danger" true "Href" "/images/1/delete" "Label" "Eliminar…")) "Meta" "1280 × 3200 · 412 KB" "Name" "Pago, paso 2" "Select" "1" "Selected" true "Src" "/images/checkout.png" "Width" 1280)
        (dict "Desc" "" "Height" 2400 "Href" "/images/2" "Menu" (list (dict "Href" "/images/2/edit" "Label" "Editar") (dict "Danger" true "Href" "/images/2/delete" "Label" "Eliminar…")) "Meta" "1280 × 2400 · 318 KB" "Name" "Página de precios" "Select" "2" "Src" "/images/pricing.png" "Width" 1280))}}

Envuelve la cuadrícula y un bulk-bar en un mismo formulario. Cada casilla envía el valor Select de su mosaico con el nombre "id"; cambia SelectName para usar otro. Dentro del formulario, los elementos del menú deben ser enlaces.

pagination

Una tira numerada de enlaces normales, para que la paginación siga funcionando con JavaScript desactivado.

En medio de una lista larga

Vista previa
<nav rst-pagination aria-label="Páginas de entradas">
  <a href="/posts?page=3" rst-pagination-step="prev"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg><span rst-pagination-word>Anterior</span></a>
  <a href="/posts?page=1">1</a>
  <span rst-pagination-gap aria-hidden="true">…</span>
  <a href="/posts?page=3" rst-pagination-wide>3</a>
  <span aria-current="page">4</span>
  <a href="/posts?page=5" rst-pagination-wide>5</a>
  <span rst-pagination-gap aria-hidden="true">…</span>
  <a href="/posts?page=9">9</a>
  <a href="/posts?page=5" rst-pagination-step="next"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg><span rst-pagination-word>Siguiente</span></a>
</nav>
{{template "pagination" dict
    "Items" (list
        (dict "Href" "/posts?page=3" "Label" "Anterior" "Rel" "prev")
        (dict "Href" "/posts?page=1" "Label" "1")
        (dict "Gap" true)
        (dict "Href" "/posts?page=3" "Label" "3")
        (dict "Current" true "Label" "4")
        (dict "Href" "/posts?page=5" "Label" "5")
        (dict "Gap" true)
        (dict "Href" "/posts?page=9" "Label" "9")
        (dict "Href" "/posts?page=5" "Label" "Siguiente" "Rel" "next"))
    "Label" "Páginas de entradas"}}

Primera página, con el nombre accesible por defecto

Vista previa
<nav rst-pagination aria-label="Paginación">
  <span rst-pagination-disabled rst-pagination-step="prev"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg><span rst-pagination-word>Anterior</span></span>
  <span aria-current="page">1</span>
  <a href="/posts?page=2">2</a>
  <a href="/posts?page=2" rst-pagination-step="next"><svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg><span rst-pagination-word>Siguiente</span></a>
</nav>
{{template "pagination" dict
    "Items" (list
        (dict "Disabled" true "Label" "Anterior" "Rel" "prev")
        (dict "Current" true "Label" "1")
        (dict "Href" "/posts?page=2" "Label" "2")
        (dict "Href" "/posts?page=2" "Label" "Siguiente" "Rel" "next"))}}

Sin Label, así que el nombre accesible del nav viene del catálogo.

empty-state

La tarjeta de estado vacío. Un estado vacío con vías para dar los primeros pasos.

Con una llamada a la acción por POST

Vista previa
<div rst-empty>
  <h2 rst-empty-title>Aún no hay nada aquí</h2>
  <p rst-empty-body>Aún no hay entradas. La primera es un buen punto de partida.</p>
  <form rst-empty-cta method="post" action="/posts/seed">
    <input type="hidden" name="csrf" value="tok-123">
    <button rst-btn="primary" type="submit">Añadir entradas de ejemplo</button>
  </form>
</div>
{{template "empty-state" dict
    "Body" "Aún no hay entradas. La primera es un buen punto de partida."
    "Title" "Aún no hay nada aquí"
    "ActionLabel" "Añadir entradas de ejemplo"
    "PostAction" "/posts/seed"
    "Hidden" (list (list "csrf" "tok-123"))}}

Solo la frase

Vista previa
<div rst-empty>
  <p rst-empty-body>Esta entrada aún no tiene comentarios.</p>
</div>
{{template "empty-state" dict "Body" "Esta entrada aún no tiene comentarios."}}