Tucano v0.37.2

Aviso

Lo que sigue vigente mientras la persona está en la pantalla: "tu suscripción vence en 3 días", "este contrato está bloqueado para edición". El toast es para lo que acaba de pasar y desaparece solo; un aviso que desaparece antes de ser leído no avisó. Solo clases, sin JavaScript.

Los valores de esta pantalla se actualizan cada 5 minutos.

Contrato firmado

Las dos partes firmaron el 12/09/2026.

La suscripción vence en 3 días

Renueva para no perder el acceso a los informes.

Contrato bloqueado para edición

Hay un cobro en disputa. Habla con el área financiera.

Ejemplos

Las piezas son opcionales: título, icono y acciones entran solo cuando hacen falta.

Sin tono

Sin is-* el aviso es neutro, para lo que no es ni bueno ni malo.

Borrador guardado a las 14:32.

Sin icono

El icono es el primer hijo, cuando existe; sin él el texto se pega al borde.

Mantenimiento programado

Sábado, de 22 h a 23 h.

Con dos acciones

Las acciones son los botones del sistema. En pantallas estrechas, bajan debajo del texto.

Hay cambios sin publicar.

Aparece después

La respuesta de un envío lleva role="alert" y se anuncia en el momento.

Cómo usar

Un .tuc-alert con el tono, el icono como primer hijo y el texto en .tuc-alert__body.

<div class="tuc-alert is-warning">
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 9v4M12 17h.01M10.3 3.9L1.8 18a2 2 0 001.7 3h17a2 2 0 001.7-3L13.7 3.9a2 2 0 00-3.4 0z"/></svg>
  <div class="tuc-alert__body">
    <p class="tuc-alert__title">La suscripción vence en 3 días</p>
    <p>Renueva para no perder el acceso.</p>
  </div>
  <div class="tuc-alert__actions">
    <a class="tuc-btn is-outline is-sm" href="/subscription/">Renovar</a>
  </div>
</div>

El icono no viene de la biblioteca: es el SVG que pegas, y hereda el color del tono. Los de esta página, para copiar:

<!-- información -->
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 16v-4M12 8h.01M12 22a10 10 0 100-20 10 10 0 000 20z"/></svg>
<!-- éxito -->
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 11.1V12a10 10 0 11-5.9-9.1M22 4L12 14l-3-3"/></svg>
<!-- alerta -->
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 9v4M12 17h.01M10.3 3.9L1.8 18a2 2 0 001.7 3h17a2 2 0 001.7-3L13.7 3.9a2 2 0 00-3.4 0z"/></svg>
<!-- peligro -->
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 22a10 10 0 100-20 10 10 0 000 20zM15 9l-6 6M9 9l6 6"/></svg>

En la plantilla de Django

El error que no pertenece a un campo, non_field_errors, es el caso más común. Y los mensajes de Django pueden convertirse en aviso, en lugar de toast, cuando necesitan quedarse en la pantalla. El tono de error de Django se llama error; el del aviso, is-danger.

{% if form.non_field_errors %}
  <div class="tuc-alert is-danger">
    <div class="tuc-alert__body">
      <p class="tuc-alert__title">No se pudo guardar</p>
      {% for error in form.non_field_errors %}<p>{{ error }}</p>{% endfor %}
    </div>
  </div>
{% endif %}

{% for m in messages %}
  <div class="tuc-alert {% if m.level_tag == 'error' %}is-danger{% else %}is-{{ m.level_tag }}{% endif %}">
    <div class="tuc-alert__body"><p>{{ m }}</p></div>
  </div>
{% endfor %}

El nivel debug se convierte en is-debug, que no tiene regla, y el aviso queda neutro.

Accesibilidad

role="alert" solo en el aviso que aparece después de la carga: la respuesta de un envío, un swap de HTMX.

Por qué no en todos

El aviso que ya viene en el HTML se lee junto con la página. Con role="alert" interrumpiría al lector de pantalla sin motivo, y en una página con tres avisos, tres veces. Lo que llega después necesita el rol justamente para interrumpir: sin él, la respuesta del envío aparece en la pantalla y nadie que use lector de pantalla se entera.

{# respuesta parcial de HTMX: aparece después, así que interrumpe #}
<div class="tuc-alert is-success" role="alert">
  <div class="tuc-alert__body"><p>Propuesta enviada a {{ customer.email }}.</p></div>
</div>

El icono lleva aria-hidden="true": quien dice lo que pasó es el texto, y el tono no puede ser la única pista.

Color

El fondo es un tinte suave del tono sobre --tuc-bg, y no el -soft transparente de los tokens: sobre una tarjeta de color o una imagen, el transparente dejaría el texto sin contraste garantizado.

Los tonos leen --tuc-info, --tuc-success, --tuc-warning y --tuc-danger, y nunca --tuc-accent. La marca puede ser de cualquier color, y el significado no puede cambiar con ella. Por eso la información ganó un tono propio: con el acento naranja, el aviso de información quedaba igual al de alerta.

Clases

Clase o atributoPara qué
.tuc-alertEl aviso. Sin tono, neutro
is-info is-success is-warning is-dangerEl tono
> svgIcono, como primer hijo: 16px, centrado en la primera línea, en el color del tono
.tuc-alert__bodyEl texto; ocupa el espacio que sobra
.tuc-alert__titlePrimera línea en negrita. El resto del cuerpo queda en el color secundario
.tuc-alert__actionsBotones a la derecha; por debajo de 40rem, bajan debajo del texto
role="alert"Solo en lo que aparece después de la carga
--tuc-alert-toneEl color que elige el tono; fondo, borde e icono salen de él