🚧 (theme): Renombra variantes de Intent
Renombra `Intent::Secondary`/`Danger` a `Neutral`/`Severe` y actualiza Badge y su CSS por defecto (basic.css) al nuevo vocabulario. Introduce el punto de extensión `Theme::intent_color()`, que traduce una `Intent` al nombre de color de la paleta propia de cada tema, con `Intent::color(cx)` como atajo de uso desde los componentes.
This commit is contained in:
parent
af53cd4b52
commit
56a6691c87
6 changed files with 116 additions and 61 deletions
|
|
@ -81,11 +81,11 @@ body {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
.badge-primary { background-color: var(--val-color--primary); }
|
.badge-primary { background-color: var(--val-color--primary); }
|
||||||
.badge-secondary { background-color: var(--val-color--secondary); }
|
.badge-neutral { background-color: var(--val-color--secondary); }
|
||||||
.badge-success { background-color: var(--val-color--success); }
|
.badge-success { background-color: var(--val-color--success); }
|
||||||
.badge-info { background-color: var(--val-color--info); }
|
.badge-info { background-color: var(--val-color--info); }
|
||||||
.badge-warning { background-color: var(--val-color--warning); }
|
.badge-warning { background-color: var(--val-color--warning); }
|
||||||
.badge-danger { background-color: var(--val-color--danger); }
|
.badge-severe { background-color: var(--val-color--danger); }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Buttons
|
* Buttons
|
||||||
|
|
@ -117,9 +117,9 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-primary,
|
.button-primary,
|
||||||
.button-secondary,
|
.button-neutral,
|
||||||
.button-success,
|
.button-success,
|
||||||
.button-danger {
|
.button-severe {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
.button-info,
|
.button-info,
|
||||||
|
|
@ -127,40 +127,40 @@ body {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
.button-primary { background-color: var(--val-color--primary); border-color: var(--val-color--primary); }
|
.button-primary { background-color: var(--val-color--primary); border-color: var(--val-color--primary); }
|
||||||
.button-secondary { background-color: var(--val-color--secondary); border-color: var(--val-color--secondary); }
|
.button-neutral { background-color: var(--val-color--secondary); border-color: var(--val-color--secondary); }
|
||||||
.button-success { background-color: var(--val-color--success); border-color: var(--val-color--success); }
|
.button-success { background-color: var(--val-color--success); border-color: var(--val-color--success); }
|
||||||
.button-info { background-color: var(--val-color--info); border-color: var(--val-color--info); }
|
.button-info { background-color: var(--val-color--info); border-color: var(--val-color--info); }
|
||||||
.button-warning { background-color: var(--val-color--warning); border-color: var(--val-color--warning); }
|
.button-warning { background-color: var(--val-color--warning); border-color: var(--val-color--warning); }
|
||||||
.button-danger { background-color: var(--val-color--danger); border-color: var(--val-color--danger); }
|
.button-severe { background-color: var(--val-color--danger); border-color: var(--val-color--danger); }
|
||||||
|
|
||||||
.button-primary:hover { background-color: color-mix(in srgb, var(--val-color--primary) 85%, black); border-color: color-mix(in srgb, var(--val-color--primary) 85%, black); }
|
.button-primary:hover { background-color: color-mix(in srgb, var(--val-color--primary) 85%, black); border-color: color-mix(in srgb, var(--val-color--primary) 85%, black); }
|
||||||
.button-secondary:hover { background-color: color-mix(in srgb, var(--val-color--secondary) 85%, black); border-color: color-mix(in srgb, var(--val-color--secondary) 85%, black); }
|
.button-neutral:hover { background-color: color-mix(in srgb, var(--val-color--secondary) 85%, black); border-color: color-mix(in srgb, var(--val-color--secondary) 85%, black); }
|
||||||
.button-success:hover { background-color: color-mix(in srgb, var(--val-color--success) 85%, black); border-color: color-mix(in srgb, var(--val-color--success) 85%, black); }
|
.button-success:hover { background-color: color-mix(in srgb, var(--val-color--success) 85%, black); border-color: color-mix(in srgb, var(--val-color--success) 85%, black); }
|
||||||
.button-info:hover { background-color: color-mix(in srgb, var(--val-color--info) 85%, black); border-color: color-mix(in srgb, var(--val-color--info) 85%, black); }
|
.button-info:hover { background-color: color-mix(in srgb, var(--val-color--info) 85%, black); border-color: color-mix(in srgb, var(--val-color--info) 85%, black); }
|
||||||
.button-warning:hover { background-color: color-mix(in srgb, var(--val-color--warning) 85%, black); border-color: color-mix(in srgb, var(--val-color--warning) 85%, black); }
|
.button-warning:hover { background-color: color-mix(in srgb, var(--val-color--warning) 85%, black); border-color: color-mix(in srgb, var(--val-color--warning) 85%, black); }
|
||||||
.button-danger:hover { background-color: color-mix(in srgb, var(--val-color--danger) 85%, black); border-color: color-mix(in srgb, var(--val-color--danger) 85%, black); }
|
.button-severe:hover { background-color: color-mix(in srgb, var(--val-color--danger) 85%, black); border-color: color-mix(in srgb, var(--val-color--danger) 85%, black); }
|
||||||
|
|
||||||
.button-outline-primary,
|
.button-outline-primary,
|
||||||
.button-outline-secondary,
|
.button-outline-neutral,
|
||||||
.button-outline-success,
|
.button-outline-success,
|
||||||
.button-outline-info,
|
.button-outline-info,
|
||||||
.button-outline-warning,
|
.button-outline-warning,
|
||||||
.button-outline-danger {
|
.button-outline-severe {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
.button-outline-primary { border-color: var(--val-color--primary); color: var(--val-color--primary); }
|
.button-outline-primary { border-color: var(--val-color--primary); color: var(--val-color--primary); }
|
||||||
.button-outline-secondary { border-color: var(--val-color--secondary); color: var(--val-color--secondary); }
|
.button-outline-neutral { border-color: var(--val-color--secondary); color: var(--val-color--secondary); }
|
||||||
.button-outline-success { border-color: var(--val-color--success); color: var(--val-color--success); }
|
.button-outline-success { border-color: var(--val-color--success); color: var(--val-color--success); }
|
||||||
.button-outline-info { border-color: var(--val-color--info); color: var(--val-color--info); }
|
.button-outline-info { border-color: var(--val-color--info); color: var(--val-color--info); }
|
||||||
.button-outline-warning { border-color: var(--val-color--warning); color: var(--val-color--warning); }
|
.button-outline-warning { border-color: var(--val-color--warning); color: var(--val-color--warning); }
|
||||||
.button-outline-danger { border-color: var(--val-color--danger); color: var(--val-color--danger); }
|
.button-outline-severe { border-color: var(--val-color--danger); color: var(--val-color--danger); }
|
||||||
|
|
||||||
.button-outline-primary:hover { background-color: var(--val-color--primary); border-color: var(--val-color--primary); color: #fff; }
|
.button-outline-primary:hover { background-color: var(--val-color--primary); border-color: var(--val-color--primary); color: #fff; }
|
||||||
.button-outline-secondary:hover { background-color: var(--val-color--secondary); border-color: var(--val-color--secondary); color: #fff; }
|
.button-outline-neutral:hover { background-color: var(--val-color--secondary); border-color: var(--val-color--secondary); color: #fff; }
|
||||||
.button-outline-success:hover { background-color: var(--val-color--success); border-color: var(--val-color--success); color: #fff; }
|
.button-outline-success:hover { background-color: var(--val-color--success); border-color: var(--val-color--success); color: #fff; }
|
||||||
.button-outline-info:hover { background-color: var(--val-color--info); border-color: var(--val-color--info); color: #000; }
|
.button-outline-info:hover { background-color: var(--val-color--info); border-color: var(--val-color--info); color: #000; }
|
||||||
.button-outline-warning:hover { background-color: var(--val-color--warning); border-color: var(--val-color--warning); color: #000; }
|
.button-outline-warning:hover { background-color: var(--val-color--warning); border-color: var(--val-color--warning); color: #000; }
|
||||||
.button-outline-danger:hover { background-color: var(--val-color--danger); border-color: var(--val-color--danger); color: #fff; }
|
.button-outline-severe:hover { background-color: var(--val-color--danger); border-color: var(--val-color--danger); color: #fff; }
|
||||||
|
|
||||||
.button-link {
|
.button-link {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ use crate::prelude::*;
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use pagetop::prelude::*;
|
/// # use pagetop::prelude::*;
|
||||||
/// let badge = Badge::labeled(Lc::n("Admin")).with_intent(Intent::Danger);
|
/// let badge = Badge::labeled(Lc::n("Admin")).with_intent(Intent::Severe);
|
||||||
///
|
///
|
||||||
/// // Equivalente usando el constructor directo del tipo.
|
/// // Equivalente usando el constructor directo del tipo.
|
||||||
/// let badge = Badge::danger(Lc::n("Admin"));
|
/// let badge = Badge::severe(Lc::n("Admin"));
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(AutoDefault, Clone, Debug, Getters)]
|
#[derive(AutoDefault, Clone, Debug, Getters)]
|
||||||
pub struct Badge {
|
pub struct Badge {
|
||||||
|
|
@ -19,7 +19,7 @@ pub struct Badge {
|
||||||
label: Lc,
|
label: Lc,
|
||||||
/// Devuelve la intención semántica del badge.
|
/// Devuelve la intención semántica del badge.
|
||||||
#[getters(copy)]
|
#[getters(copy)]
|
||||||
#[default(Intent::Secondary)]
|
#[default(Intent::Neutral)]
|
||||||
intent: Intent,
|
intent: Intent,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,10 +33,10 @@ impl Component for Badge {
|
||||||
self.props.get_id()
|
self.props.get_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(&mut self, _cx: &Context) {
|
fn setup(&mut self, cx: &Context) {
|
||||||
self.alter_prop(PropsOp::prepend_classes(util::join!(
|
self.alter_prop(PropsOp::prepend_classes(util::join!(
|
||||||
"badge badge-",
|
"badge badge-",
|
||||||
self.intent().as_str()
|
self.intent().color(cx)
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,11 +67,11 @@ impl Badge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Crea un badge de tipo *secondary* con la etiqueta indicada.
|
/// Crea un badge de tipo *neutral* con la etiqueta indicada.
|
||||||
pub fn secondary(label: Lc) -> Self {
|
pub fn neutral(label: Lc) -> Self {
|
||||||
Self {
|
Self {
|
||||||
label,
|
label,
|
||||||
intent: Intent::Secondary,
|
intent: Intent::Neutral,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -103,11 +103,11 @@ impl Badge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Crea un badge de tipo *danger* con la etiqueta indicada.
|
/// Crea un badge de tipo *severe* con la etiqueta indicada.
|
||||||
pub fn danger(label: Lc) -> Self {
|
pub fn severe(label: Lc) -> Self {
|
||||||
Self {
|
Self {
|
||||||
label,
|
label,
|
||||||
intent: Intent::Danger,
|
intent: Intent::Severe,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,14 @@
|
||||||
//!
|
//!
|
||||||
//! # Temas hijo, herencia y componentes
|
//! # Temas hijo, herencia y componentes
|
||||||
//!
|
//!
|
||||||
//! PageTop permite crear **temas hijo** que refinan el comportamiento de su tema padre. Un tema
|
//! PageTop permite crear **temas hijo** que refinan el comportamiento de su tema padre,
|
||||||
//! hijo hereda automáticamente todos los métodos del padre y puede sobrescribirlos selectivamente.
|
//! identificado por [`Theme::parent()`]. Un tema hijo hereda automáticamente todos los métodos del
|
||||||
//! Esta herencia sólo determina qué implementación de sus métodos se usa cuando el tema hijo no los
|
//! padre y puede sobrescribirlos selectivamente. Esta herencia determina qué implementación de sus
|
||||||
//! sobrescribe (como el renderizado del `<body>` y del `<head>`, los recursos incorporados, el uso
|
//! métodos se usa cuando el tema hijo no los sobrescribe (ya sea el renderizado del `<body>` o del
|
||||||
//! de [`Theme::handle_component()`], las páginas de error, etc.). Un tema hijo puede ser a su vez
|
//! `<head>`, la definición de los recursos necesarios, la asignación de colores por intención vía
|
||||||
//! padre de otro, basta declararlo cada vez con [`Theme::parent()`].
|
//! [`Theme::intent_color()`], la captura de componentes con [`Theme::handle_component()`], las
|
||||||
|
//! páginas de error, etc.). Un tema hijo puede ser a su vez padre de otro, basta declararlo cada
|
||||||
|
//! vez con [`Theme::parent()`].
|
||||||
//!
|
//!
|
||||||
//! Como `parent()` se resuelve en tiempo de ejecución, PageTop no puede descartar en compilación
|
//! Como `parent()` se resuelve en tiempo de ejecución, PageTop no puede descartar en compilación
|
||||||
//! referencias circulares (un tema acaba siendo padre de sí mismo, directa o transitivamente). Ese
|
//! referencias circulares (un tema acaba siendo padre de sí mismo, directa o transitivamente). Ese
|
||||||
|
|
@ -48,8 +50,8 @@
|
||||||
//! devuelva `Some(&Self)`. Basta con un `impl Theme for MyTheme {}` vacío, ya que todos los
|
//! devuelva `Some(&Self)`. Basta con un `impl Theme for MyTheme {}` vacío, ya que todos los
|
||||||
//! métodos de [`Theme`] tienen implementación por defecto.
|
//! métodos de [`Theme`] tienen implementación por defecto.
|
||||||
//!
|
//!
|
||||||
//! Un tema puede personalizarse en tres pasos, cada uno necesario sólo si lo que ofrece PageTop por
|
//! Un tema puede personalizarse en cinco pasos, cada uno necesario sólo si lo que ofrece PageTop
|
||||||
//! defecto no basta:
|
//! por defecto no basta:
|
||||||
//!
|
//!
|
||||||
//! 1. **Definir regiones nuevas**. Por defecto, PageTop define [`CoreRegions`] (`Header`, `Aside`,
|
//! 1. **Definir regiones nuevas**. Por defecto, PageTop define [`CoreRegions`] (`Header`, `Aside`,
|
||||||
//! `Content`, `Footer`) como regiones de plantilla siempre disponibles, y [`ReservedRegions`]
|
//! `Content`, `Footer`) como regiones de plantilla siempre disponibles, y [`ReservedRegions`]
|
||||||
|
|
@ -75,6 +77,21 @@
|
||||||
//! ejemplo, [`CoreTemplates`] o el propio *enum* del tema). `pagetop-bootsier` hace exactamente
|
//! ejemplo, [`CoreTemplates`] o el propio *enum* del tema). `pagetop-bootsier` hace exactamente
|
||||||
//! esto para maquetar `Standard` y `Admin` de forma distinta, sin necesitar sus propias
|
//! esto para maquetar `Standard` y `Admin` de forma distinta, sin necesitar sus propias
|
||||||
//! variantes de plantilla.
|
//! variantes de plantilla.
|
||||||
|
//! 4. **Traducir [`Intent`] a la paleta de colores propia del tema** sobrescribiendo
|
||||||
|
//! [`Theme::intent_color()`]. Por defecto, este método devuelve el vocabulario semántico de
|
||||||
|
//! [`Intent`] (`"primary"`, `"severe"`, etc.); un tema con su propio catálogo de colores (por
|
||||||
|
//! ejemplo, uno basado en Bootstrap) debe traducir cada variante al nombre que le corresponda en
|
||||||
|
//! su paleta. Los componentes que generan clases CSS a partir de una [`Intent`] (`Button`,
|
||||||
|
//! `Badge`, `Dropdown`, etc.) consultan este método a través de [`Intent::color()`], así que la
|
||||||
|
//! clase resultante ya nace en la paleta del tema activo.
|
||||||
|
//! 5. **Reexportar, extender o añadir componentes**. Un tema puede reexportar tal cual los
|
||||||
|
//! componentes propios de PageTop que no requieran adaptación, extenderlos con un trait propio
|
||||||
|
//! para añadir métodos exclusivos (guardando su estado en valores extra con
|
||||||
|
//! [`PropsOp::set_extra()`](crate::html::PropsOp::set_extra) para consumirlos en el
|
||||||
|
//! `setup()`/`render()` vía [`Theme::handle_component()`]), o aportar componentes propios.
|
||||||
|
//! `pagetop-bootsier` combina las tres estrategias: reexporta `Form`/`Fieldset` sin cambios,
|
||||||
|
//! extiende `Button`/`Badge`/`Dropdown`/`Nav`/`Navbar` con sus propios traits (`ButtonBootsier`,
|
||||||
|
//! `BadgeBootsier`, etc.), y añade componentes propios como `Offcanvas`.
|
||||||
//!
|
//!
|
||||||
//! Para forzar una plantilla completamente distinta en una página concreta, se puede llamar
|
//! Para forzar una plantilla completamente distinta en una página concreta, se puede llamar
|
||||||
//! manualmente a [`with_template()`](crate::core::component::Contextual::with_template).
|
//! manualmente a [`with_template()`](crate::core::component::Contextual::with_template).
|
||||||
|
|
@ -86,7 +103,7 @@
|
||||||
//! plantilla distinta.
|
//! plantilla distinta.
|
||||||
//!
|
//!
|
||||||
//! El resto del comportamiento de un tema (por ejemplo, el renderizado del `<head>`) se sobrescribe
|
//! El resto del comportamiento de un tema (por ejemplo, el renderizado del `<head>`) se sobrescribe
|
||||||
//! de forma independiente de estos tres pasos y no es necesario para tener un tema funcional.
|
//! de forma independiente de estos pasos y no es necesario para tener un tema funcional.
|
||||||
//!
|
//!
|
||||||
//! # Componentes que se procesan en todas las páginas
|
//! # Componentes que se procesan en todas las páginas
|
||||||
//!
|
//!
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::base::component::{Html, Intro, IntroOpening, layout};
|
||||||
use crate::core::component::{ChildOp, Component, ComponentError, ComponentRender};
|
use crate::core::component::{ChildOp, Component, ComponentError, ComponentRender};
|
||||||
use crate::core::component::{Context, Contextual};
|
use crate::core::component::{Context, Contextual};
|
||||||
use crate::core::extension::Extension;
|
use crate::core::extension::Extension;
|
||||||
use crate::core::theme::CoreRegions;
|
use crate::core::theme::{CoreRegions, Intent};
|
||||||
use crate::global;
|
use crate::global;
|
||||||
use crate::html::{Markup, html};
|
use crate::html::{Markup, html};
|
||||||
use crate::locale::Lc;
|
use crate::locale::Lc;
|
||||||
|
|
@ -65,6 +65,34 @@ pub trait Theme: Extension + Send + Sync {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Traduce una [`Intent`] al nombre de color de la paleta propia del tema.
|
||||||
|
///
|
||||||
|
/// `Intent` no define ninguna cadena propia. Cada tema decide qué nombre le corresponde a cada
|
||||||
|
/// variante en su paleta (p. ej. un tema basado en Bootstrap traduce `Severe` a `"danger"`).
|
||||||
|
/// Los componentes que generan clases CSS a partir de una `Intent` (`Button`, `Badge`,
|
||||||
|
/// `Dropdown`, etc.) no llaman a este método directamente en su `setup()`, usan mejor
|
||||||
|
/// [`Intent::color()`](crate::core::theme::Intent::color) como la forma más sencilla de obtener
|
||||||
|
/// este mismo valor a través de [`Context::theme()`](crate::core::component::Context::theme),
|
||||||
|
/// para que la clase resultante ya nazca en la paleta del tema activo.
|
||||||
|
///
|
||||||
|
/// La implementación por defecto devuelve el vocabulario semántico propio de PageTop
|
||||||
|
/// (`"primary"`, `"severe"`, etc.), que actúa como paleta base cuando ningún tema la
|
||||||
|
/// sobrescribe.
|
||||||
|
#[rustfmt::skip]
|
||||||
|
fn intent_color(&self, intent: Intent) -> &'static str {
|
||||||
|
if let Some(parent) = self.parent() {
|
||||||
|
return parent.intent_color(intent);
|
||||||
|
}
|
||||||
|
match intent {
|
||||||
|
Intent::Primary => "primary",
|
||||||
|
Intent::Neutral => "neutral",
|
||||||
|
Intent::Info => "info",
|
||||||
|
Intent::Success => "success",
|
||||||
|
Intent::Warning => "warning",
|
||||||
|
Intent::Severe => "severe",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Acciones específicas del tema antes de renderizar el `<body>` de la página.
|
/// Acciones específicas del tema antes de renderizar el `<body>` de la página.
|
||||||
///
|
///
|
||||||
/// Es un buen lugar para inicializar o ajustar recursos en función del contexto de la página,
|
/// Es un buen lugar para inicializar o ajustar recursos en función del contexto de la página,
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,41 @@
|
||||||
use crate::AutoDefault;
|
use crate::AutoDefault;
|
||||||
|
use crate::core::component::{Context, Contextual};
|
||||||
|
|
||||||
/// Intención semántica de un componente visual.
|
/// Intención semántica de un componente visual.
|
||||||
///
|
///
|
||||||
/// Representa la intención que pretende comunicar un componente (énfasis principal, confirmación de
|
/// Describe *qué comunica* un componente, y cada tema traduce la intención a su propia paleta de
|
||||||
/// un evento exitoso, aviso, peligro, etc.). Cada tema decidirá cómo pintarlo.
|
/// colores. Define un vocabulario con variantes por énfasis (`Primary`, `Neutral`), un canal
|
||||||
|
/// informativo (`Info`) y una escala de severidad (`Success`, `Warning`, `Severe`).
|
||||||
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
||||||
pub enum Intent {
|
pub enum Intent {
|
||||||
|
/// Énfasis principal, suele ser la acción que más destaca a la vista.
|
||||||
#[default]
|
#[default]
|
||||||
Primary,
|
Primary,
|
||||||
Secondary,
|
/// Presencia sin énfasis, una opción discreta o normal.
|
||||||
Success,
|
Neutral,
|
||||||
|
/// Informa de algo que merece leerse, ajeno a la escala de severidad. Encaja en notas o avisos
|
||||||
|
/// informativos.
|
||||||
Info,
|
Info,
|
||||||
|
/// Destaca algo que ha ido bien, un estado favorable o un camino afirmativo. En una alerta
|
||||||
|
/// podría indicar la confirmación de una operación correcta o un estado saludable; en un botón,
|
||||||
|
/// la acción que confirma o aprueba algo positivamente.
|
||||||
|
Success,
|
||||||
|
/// Precaución, representa algo que requiere atención o cuidado. En una alerta, sería un
|
||||||
|
/// problema no bloqueante o un aviso; en un botón, una acción que conviene meditar sin llegar a
|
||||||
|
/// ser destructiva.
|
||||||
Warning,
|
Warning,
|
||||||
Danger,
|
/// Algo va mal, es peligroso o destructivo. En una alerta sería un error o un fallo bloqueante;
|
||||||
|
/// en un botón, la acción destructiva o irreversible (p. ej. eliminar).
|
||||||
|
Severe,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Intent {
|
impl Intent {
|
||||||
/// Devuelve el nombre de la intención (`"primary"`, `"danger"`, etc.).
|
/// Devuelve el nombre del color asociado a la intención en el tema activo del contexto actual.
|
||||||
#[rustfmt::skip]
|
///
|
||||||
pub const fn as_str(&self) -> &'static str {
|
/// Atajo de [`Theme::intent_color()`](crate::core::theme::Theme::intent_color) a través de
|
||||||
match self {
|
/// [`Context::theme()`]. La intención no tiene una cadena propia, es el tema activo quien
|
||||||
Self::Primary => "primary",
|
/// decide su traducción.
|
||||||
Self::Secondary => "secondary",
|
pub fn color(&self, cx: &Context) -> &'static str {
|
||||||
Self::Success => "success",
|
cx.theme().intent_color(*self)
|
||||||
Self::Info => "info",
|
|
||||||
Self::Warning => "warning",
|
|
||||||
Self::Danger => "danger",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,22 +28,22 @@ async fn renders_as_a_span_element() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pagetop::test]
|
#[pagetop::test]
|
||||||
async fn default_intent_is_secondary() {
|
async fn default_intent_is_neutral() {
|
||||||
let mut badge = Badge::labeled(Lc::n("Admin"));
|
let mut badge = Badge::labeled(Lc::n("Admin"));
|
||||||
let html = badge.render(&mut Context::default()).await.into_string();
|
let html = badge.render(&mut Context::default()).await.into_string();
|
||||||
|
|
||||||
assert!(html.contains(r#"class="badge badge-secondary""#));
|
assert!(html.contains(r#"class="badge badge-neutral""#));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pagetop::test]
|
#[pagetop::test]
|
||||||
async fn each_direct_constructor_sets_its_intent() {
|
async fn each_direct_constructor_sets_its_intent() {
|
||||||
let cases = [
|
let cases = [
|
||||||
(Badge::primary(Lc::n("x")), "badge-primary"),
|
(Badge::primary(Lc::n("x")), "badge-primary"),
|
||||||
(Badge::secondary(Lc::n("x")), "badge-secondary"),
|
(Badge::neutral(Lc::n("x")), "badge-neutral"),
|
||||||
(Badge::success(Lc::n("x")), "badge-success"),
|
(Badge::success(Lc::n("x")), "badge-success"),
|
||||||
(Badge::info(Lc::n("x")), "badge-info"),
|
(Badge::info(Lc::n("x")), "badge-info"),
|
||||||
(Badge::warning(Lc::n("x")), "badge-warning"),
|
(Badge::warning(Lc::n("x")), "badge-warning"),
|
||||||
(Badge::danger(Lc::n("x")), "badge-danger"),
|
(Badge::severe(Lc::n("x")), "badge-severe"),
|
||||||
];
|
];
|
||||||
for (mut badge, expected_class) in cases {
|
for (mut badge, expected_class) in cases {
|
||||||
let html = badge.render(&mut Context::default()).await.into_string();
|
let html = badge.render(&mut Context::default()).await.into_string();
|
||||||
|
|
@ -56,16 +56,16 @@ async fn each_direct_constructor_sets_its_intent() {
|
||||||
|
|
||||||
#[pagetop::test]
|
#[pagetop::test]
|
||||||
async fn with_intent_overrides_the_default() {
|
async fn with_intent_overrides_the_default() {
|
||||||
let mut badge = Badge::labeled(Lc::n("Admin")).with_intent(Intent::Danger);
|
let mut badge = Badge::labeled(Lc::n("Admin")).with_intent(Intent::Severe);
|
||||||
let html = badge.render(&mut Context::default()).await.into_string();
|
let html = badge.render(&mut Context::default()).await.into_string();
|
||||||
|
|
||||||
assert!(html.contains(r#"class="badge badge-danger""#));
|
assert!(html.contains(r#"class="badge badge-severe""#));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pagetop::test]
|
#[pagetop::test]
|
||||||
async fn direct_constructor_is_equivalent_to_labeled_with_intent() {
|
async fn direct_constructor_is_equivalent_to_labeled_with_intent() {
|
||||||
let mut from_constructor = Badge::danger(Lc::n("Admin"));
|
let mut from_constructor = Badge::severe(Lc::n("Admin"));
|
||||||
let mut from_builder = Badge::labeled(Lc::n("Admin")).with_intent(Intent::Danger);
|
let mut from_builder = Badge::labeled(Lc::n("Admin")).with_intent(Intent::Severe);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
from_constructor
|
from_constructor
|
||||||
|
|
@ -89,9 +89,9 @@ async fn with_id_sets_the_identifier() {
|
||||||
|
|
||||||
#[pagetop::test]
|
#[pagetop::test]
|
||||||
async fn with_prop_adds_extra_classes_alongside_the_intent_class() {
|
async fn with_prop_adds_extra_classes_alongside_the_intent_class() {
|
||||||
let mut badge = Badge::danger(Lc::n("Admin")).with_prop(PropsOp::add_classes("custom"));
|
let mut badge = Badge::severe(Lc::n("Admin")).with_prop(PropsOp::add_classes("custom"));
|
||||||
let html = badge.render(&mut Context::default()).await.into_string();
|
let html = badge.render(&mut Context::default()).await.into_string();
|
||||||
|
|
||||||
assert!(html.contains("badge-danger"));
|
assert!(html.contains("badge-severe"));
|
||||||
assert!(html.contains("custom"));
|
assert!(html.contains("custom"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue