From e24b9ab9debb65a63a4289b1da83e1fe80a7329d Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sat, 22 Aug 2026 09:44:28 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(pagetop):=20Logotipo=20em?= =?UTF-8?q?bebido=20y=20Badge=20en=20Intent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `PageTopSvg::markup_with()` fusiona `Props` y controla la etiqueta accesible directamente en el ``. - `Image` ya no duplica accesibilidad para el logotipo y corrige el `alt` vacío en el resto de fuentes (Responsive/Thumbnail/Plain). - Sustituye `BadgeKind` y el `ColorName`/`IntoColor` de `core/theme` por un `Intent` compartido. --- assets/css/basic.css | 37 ++++++++++ extensions/pagetop-bootsier/src/theme/bs.rs | 2 +- .../pagetop-bootsier/src/theme/bs/badge.rs | 18 ++--- src/base/component.rs | 2 +- src/base/component/badge.rs | 56 +++++---------- src/base/component/brand.rs | 41 ++++++----- src/base/component/image/component.rs | 38 +++++++---- src/base/component/intro.rs | 4 +- src/core/theme.rs | 4 +- src/core/theme/color.rs | 68 ------------------- src/core/theme/intent.rs | 31 +++++++++ src/html/logo.rs | 63 ++++++++++++----- src/locale/en-US/theme.ftl | 4 +- src/locale/es-ES/theme.ftl | 4 +- tests/component_badge.rs | 14 ++-- 15 files changed, 199 insertions(+), 187 deletions(-) delete mode 100644 src/core/theme/color.rs create mode 100644 src/core/theme/intent.rs diff --git a/assets/css/basic.css b/assets/css/basic.css index 3e199708..818db21a 100644 --- a/assets/css/basic.css +++ b/assets/css/basic.css @@ -44,6 +44,23 @@ body { -webkit-tap-highlight-color: transparent; } +/* + * Brand component + */ + +.brand { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--val-color--text); + font-size: 1.75rem; + font-weight: 600; + text-decoration: none; +} +.brand .image { + display: flex; +} + /* * Badge component */ @@ -280,6 +297,26 @@ input:disabled + label { border: 0; } +/* + * Image component + */ + +.image { + vertical-align: middle; +} +.image-fluid { + max-width: 100%; + height: auto; +} +.image-thumbnail { + max-width: 100%; + height: auto; + padding: 0.25rem; + background-color: var(--val-color--bg); + border: 1px solid var(--val-color--border); + border-radius: 0.375rem; +} + /* * Messages component */ diff --git a/extensions/pagetop-bootsier/src/theme/bs.rs b/extensions/pagetop-bootsier/src/theme/bs.rs index ae101e55..8fabce2b 100644 --- a/extensions/pagetop-bootsier/src/theme/bs.rs +++ b/extensions/pagetop-bootsier/src/theme/bs.rs @@ -2,7 +2,7 @@ // Badge. pub(crate) mod badge; -pub use badge::{Badge, BadgeKind}; +pub use badge::Badge; // Button. mod button; diff --git a/extensions/pagetop-bootsier/src/theme/bs/badge.rs b/extensions/pagetop-bootsier/src/theme/bs/badge.rs index 615119c9..43dceae8 100644 --- a/extensions/pagetop-bootsier/src/theme/bs/badge.rs +++ b/extensions/pagetop-bootsier/src/theme/bs/badge.rs @@ -1,18 +1,14 @@ use pagetop::prelude::*; -pub use pagetop::base::component::{Badge, BadgeKind}; +pub use pagetop::base::component::Badge; // **< Badge SETUP >******************************************************************************** -#[rustfmt::skip] pub(crate) fn setup(badge: &mut Badge) { - let (old, new) = match badge.kind() { - BadgeKind::Primary => ("badge-primary", "text-bg-primary"), - BadgeKind::Secondary => ("badge-secondary", "text-bg-secondary"), - BadgeKind::Success => ("badge-success", "text-bg-success"), - BadgeKind::Info => ("badge-info", "text-bg-info"), - BadgeKind::Warning => ("badge-warning", "text-bg-warning"), - BadgeKind::Danger => ("badge-danger", "text-bg-danger"), - }; - badge.alter_prop(PropsOp::replace_classes(old, new)); + let intent = badge.intent().as_str(); + + badge.alter_prop(PropsOp::replace_classes( + util::join!("badge-", intent), + util::join!("text-bg-", intent), + )); } diff --git a/src/base/component.rs b/src/base/component.rs index 53ccafdf..e01ed9af 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -3,7 +3,7 @@ pub mod layout; mod badge; -pub use badge::{Badge, BadgeKind}; +pub use badge::Badge; mod brand; pub use brand::Brand; diff --git a/src/base/component/badge.rs b/src/base/component/badge.rs index 12fa7ca8..a01a61c5 100644 --- a/src/base/component/badge.rs +++ b/src/base/component/badge.rs @@ -1,28 +1,12 @@ use crate::prelude::*; -// **< BadgeKind >********************************************************************************** - -/// Tipo de [`Badge`]. -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub enum BadgeKind { - Primary, - #[default] - Secondary, - Success, - Info, - Warning, - Danger, -} - -// **< Badge >************************************************************************************** - /// Componente para mostrar una **etiqueta corta informativa** (*badge*). /// /// # Ejemplo /// /// ```rust,no_run /// # use pagetop::prelude::*; -/// let badge = Badge::labeled(Lc::n("Admin")).with_kind(BadgeKind::Danger); +/// let badge = Badge::labeled(Lc::n("Admin")).with_intent(Intent::Danger); /// /// // Equivalente usando el constructor directo del tipo. /// let badge = Badge::danger(Lc::n("Admin")); @@ -33,9 +17,10 @@ pub struct Badge { props: Props, /// Devuelve la etiqueta del badge. label: Lc, - /// Devuelve el tipo del badge. + /// Devuelve la intención semántica del badge. #[getters(copy)] - kind: BadgeKind, + #[default(Intent::Secondary)] + intent: Intent, } #[async_trait] @@ -48,16 +33,11 @@ impl Component for Badge { self.props.get_id() } - #[rustfmt::skip] fn setup(&mut self, _cx: &Context) { - self.alter_prop(PropsOp::prepend_classes(match self.kind() { - BadgeKind::Primary => "badge badge-primary", - BadgeKind::Secondary => "badge badge-secondary", - BadgeKind::Success => "badge badge-success", - BadgeKind::Info => "badge badge-info", - BadgeKind::Warning => "badge badge-warning", - BadgeKind::Danger => "badge badge-danger", - })); + self.alter_prop(PropsOp::prepend_classes(util::join!( + "badge badge-", + self.intent().as_str() + ))); } async fn prepare(&self, cx: &mut Context) -> Result { @@ -70,7 +50,7 @@ impl Component for Badge { } impl Badge { - /// Crea un badge predeterminado (`BadgeKind::default()`) con la etiqueta indicada. + /// Crea un badge predeterminado (`Intent::default()`) con la etiqueta indicada. pub fn labeled(label: Lc) -> Self { Self { label, @@ -82,7 +62,7 @@ impl Badge { pub fn primary(label: Lc) -> Self { Self { label, - kind: BadgeKind::Primary, + intent: Intent::Primary, ..Default::default() } } @@ -91,7 +71,7 @@ impl Badge { pub fn secondary(label: Lc) -> Self { Self { label, - kind: BadgeKind::Secondary, + intent: Intent::Secondary, ..Default::default() } } @@ -100,7 +80,7 @@ impl Badge { pub fn success(label: Lc) -> Self { Self { label, - kind: BadgeKind::Success, + intent: Intent::Success, ..Default::default() } } @@ -109,7 +89,7 @@ impl Badge { pub fn info(label: Lc) -> Self { Self { label, - kind: BadgeKind::Info, + intent: Intent::Info, ..Default::default() } } @@ -118,7 +98,7 @@ impl Badge { pub fn warning(label: Lc) -> Self { Self { label, - kind: BadgeKind::Warning, + intent: Intent::Warning, ..Default::default() } } @@ -127,7 +107,7 @@ impl Badge { pub fn danger(label: Lc) -> Self { Self { label, - kind: BadgeKind::Danger, + intent: Intent::Danger, ..Default::default() } } @@ -155,10 +135,10 @@ impl Badge { self } - /// Establece el tipo del badge. + /// Establece la intención semántica del badge. #[builder_fn] - pub fn with_kind(mut self, kind: BadgeKind) -> Self { - self.kind = kind; + pub fn with_intent(mut self, intent: Intent) -> Self { + self.intent = intent; self } } diff --git a/src/base/component/brand.rs b/src/base/component/brand.rs index fa7398b1..a1113ef3 100644 --- a/src/base/component/brand.rs +++ b/src/base/component/brand.rs @@ -2,14 +2,14 @@ use crate::prelude::*; /// Componente para mostrar la **identidad de marca** de un sitio o aplicación. /// -/// Combina una imagen, un título y un eslogan opcional, típicamente en la cabecera de la página o -/// dentro de una barra de navegación proporcionada por un tema. +/// Combina una imagen y un título, típicamente en la cabecera de la página o dentro de una barra de +/// navegación. /// /// - Si hay ruta ([`with_route()`]), el bloque completo actúa como enlace. Por defecto enlaza a la /// raíz del sitio (`/`). -/// - Si no hay imagen ([`with_image()`]) ni título ([`with_title()`]), la marca de identidad no se -/// renderiza. -/// - El eslogan ([`with_slogan()`]) es opcional; por defecto no tiene contenido. +/// - Si no tiene ningún contenido (ni imagen ni título), la marca de identidad no se renderiza. +/// - El título predefinido es el nombre de la aplicación ([`global::SETTINGS.app.name`]). La imagen +/// es opcional, por defecto no tiene contenido. /// /// # Ejemplo /// @@ -17,15 +17,13 @@ use crate::prelude::*; /// use pagetop::prelude::*; /// /// let brand = Brand::new() -/// .with_image(Some(Image::with(image::Source::logo(PageTopSvg::Color)))) +/// .with_image(image::Source::logo(PageTopSvg::Color)) /// .with_title(Lc::n("PageTop")) /// .with_route(Route::from("/")); /// ``` /// /// [`with_route()`]: Self::with_route -/// [`with_image()`]: Self::with_image -/// [`with_title()`]: Self::with_title -/// [`with_slogan()`]: Self::with_slogan +/// [`global::SETTINGS.app.name`]: crate::global::App::name #[derive(AutoDefault, Clone, Debug, Getters)] pub struct Brand { /// Devuelve identificador, clases CSS, atributos HTML y valores extra del componente. @@ -35,8 +33,6 @@ pub struct Brand { /// Devuelve el título de la identidad de marca. #[default(_code = "Lc::n(&global::SETTINGS.app.name)")] title: Lc, - /// Devuelve el eslogan de la marca. - slogan: Lc, /// Devuelve la ruta asociada a la marca (si existe). #[default(_code = "Some(\"/\".into())")] route: Option, @@ -59,15 +55,23 @@ impl Component for Brand { async fn prepare(&self, cx: &mut Context) -> Result { let image = self.image().render(cx).await; let title = self.title().using(cx); - if image.is_empty() && title.is_empty() { + let inner_brand = html! { + (image) + @if !title.is_empty() { + @if !image.is_empty() { + (" ") + } + span class="brand-title" { (title) } + } + }; + if inner_brand.is_empty() { return Ok(html! {}); } - let slogan = self.slogan().using(cx); Ok(html! { @if let Some(route) = self.route() { - a (self.props()) href=(route.resolve(cx)) { (image) (title) (slogan) } + a (self.props()) href=(route.resolve(cx)) { (inner_brand) } } @else { - span (self.props()) { (image) (title) (slogan) } + span (self.props()) { (inner_brand) } } }) } @@ -104,13 +108,6 @@ impl Brand { self } - /// Define el eslogan de la marca. - #[builder_fn] - pub fn with_slogan(mut self, slogan: Lc) -> Self { - self.slogan = slogan; - self - } - /// Define la ruta de destino. Si es `None`, la marca no será un enlace. #[builder_fn] pub fn with_route(mut self, route: impl Into>) -> Self { diff --git a/src/base/component/image/component.rs b/src/base/component/image/component.rs index 220a079e..344df838 100644 --- a/src/base/component/image/component.rs +++ b/src/base/component/image/component.rs @@ -49,6 +49,13 @@ impl Component for Image { image::Source::Thumbnail(_) => "image image-thumbnail", image::Source::Plain(_) => "image", })); + + // Se asigna un tamaño predefinido para el logotipo que `with_size()` puede sobrescribir. + if matches!(self.source(), image::Source::Logo(_)) { + self.alter_prop(PropsOp::add_style("width", "1.25em")); + self.alter_prop(PropsOp::add_style("height", "1.25em")); + } + // El tamaño se aplica como declaraciones `style` individuales sobre `Props`. match *self.size() { image::Size::Auto => {} @@ -72,18 +79,9 @@ impl Component for Image { async fn prepare(&self, cx: &mut Context) -> Result { let alt_text = self.alternative().lookup(cx).unwrap_or_default(); let source = match self.source() { - image::Source::Logo(logo) => { - let is_decorative = alt_text.is_empty(); - return Ok(html! { - span - (self.props()) - role=[(!is_decorative).then_some("img")] - aria-label=[(!is_decorative).then_some(alt_text)] - aria-hidden=[is_decorative.then_some("true")] - { - (logo.markup(cx)) - } - }); + image::Source::Logo(svg) => { + let label = (!alt_text.is_empty()).then_some(alt_text.as_str()); + return Ok(svg.markup_with(self.props(), label)); } image::Source::Responsive(source) => Some(source), image::Source::Thumbnail(source) => Some(source), @@ -144,3 +142,19 @@ impl Image { self } } + +impl From for Image { + /// Igual que [`Image::with()`]. + fn from(source: image::Source) -> Self { + Self::with(source) + } +} + +impl From for Option { + /// Permite pasar un [`image::Source`] directamente donde se espera `impl Into>` + /// (p. ej. [`Brand::with_image()`](super::super::Brand::with_image)), sin construir la + /// [`Image`] a mano. + fn from(source: image::Source) -> Self { + Some(Image::with(source)) + } +} diff --git a/src/base/component/intro.rs b/src/base/component/intro.rs index f2c306c1..e339fd27 100644 --- a/src/base/component/intro.rs +++ b/src/base/component/intro.rs @@ -148,7 +148,7 @@ impl Component for Intro { } aside class="intro-header-img" aria-hidden="true" { div class="intro-header-mascot" { - (PageTopSvg::Color.markup(cx)) + (PageTopSvg::Color.markup()) } } } @@ -201,7 +201,7 @@ impl Component for Intro { div class="intro-footer" { section class="intro-footer-body" { div class="intro-footer-logo" { - (PageTopSvg::LineLight.markup(cx)) + (PageTopSvg::LineLight.markup()) } div class="intro-footer-links" { a href="https://crates.io/crates/pagetop" target="_blank" rel="noopener noreferrer" { ("Crates.io") } diff --git a/src/core/theme.rs b/src/core/theme.rs index bad50216..09dd0a2e 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -117,8 +117,8 @@ //! //! [`ReservedRegions`]: crate::response::ReservedRegions -mod color; -pub use color::{ColorName, CoreColors, IntoColor}; +mod intent; +pub use intent::Intent; mod layout; pub use layout::{CoreRegions, RegionName, RegionRef}; diff --git a/src/core/theme/color.rs b/src/core/theme/color.rs deleted file mode 100644 index 62cf5cd0..00000000 --- a/src/core/theme/color.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::AutoDefault; - -// **< ColorName >********************************************************************************** - -/// Interfaz común para los colores de la paleta de un tema. -/// -/// PageTop ofrece una implementación predeterminada en [`CoreColors`], aunque probablemente cada -/// tema proporcionará su propia lista de colores implementando este trait. -pub trait ColorName { - /// Devuelve el nombre asociado al color (p. ej. `"primary"`, `"danger"`, etc.). Normalmente se - /// usará para generar la clase CSS del componente. - fn name(self) -> &'static str; -} - -// **< IntoColor >********************************************************************************** - -/// Convierte un color, o su ausencia, en el nombre ya resuelto. -/// -/// Permite que un método como `with_color(color: impl IntoColor)` acepte indistintamente un color -/// directo (`CoreColors::Danger`) o uno opcional (`Some(CoreColors::Danger)`, o `None` para no -/// aplicar ninguno). -/// -/// Evita la ambigüedad de `impl From for T` junto con `impl From for Option` al -/// resolver un `C` genérico acotado por [`ColorName`]. Al ser [`IntoColor`] un trait propio, -/// ninguna implementación de [`ColorName`] cubre nunca `Option` y la resolución no es ambigua. -pub trait IntoColor { - /// Devuelve el nombre del color ya resuelto, o `None` si no se aplica ninguno. - fn into_color(self) -> Option<&'static str>; -} - -impl IntoColor for C { - fn into_color(self) -> Option<&'static str> { - Some(self.name()) - } -} - -impl IntoColor for Option { - fn into_color(self) -> Option<&'static str> { - self.map(ColorName::name) - } -} - -// **< CoreColors >********************************************************************************* - -/// Paleta de colores predeterminada de PageTop. -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub enum CoreColors { - #[default] - Primary, - Secondary, - Success, - Info, - Warning, - Danger, -} - -impl ColorName for CoreColors { - fn name(self) -> &'static str { - match self { - Self::Primary => "primary", - Self::Secondary => "secondary", - Self::Success => "success", - Self::Info => "info", - Self::Warning => "warning", - Self::Danger => "danger", - } - } -} diff --git a/src/core/theme/intent.rs b/src/core/theme/intent.rs new file mode 100644 index 00000000..ff6e4626 --- /dev/null +++ b/src/core/theme/intent.rs @@ -0,0 +1,31 @@ +use crate::AutoDefault; + +/// Intención semántica de un componente visual. +/// +/// Representa la intención que pretende comunicar un componente (énfasis principal, confirmación de +/// un evento exitoso, aviso, peligro, etc.). Cada tema decidirá cómo pintarlo. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Intent { + #[default] + Primary, + Secondary, + Success, + Info, + Warning, + Danger, +} + +impl Intent { + /// Devuelve el nombre de la intención (`"primary"`, `"danger"`, etc.). + #[rustfmt::skip] + pub const fn as_str(&self) -> &'static str { + match self { + Self::Primary => "primary", + Self::Secondary => "secondary", + Self::Success => "success", + Self::Info => "info", + Self::Warning => "warning", + Self::Danger => "danger", + } + } +} diff --git a/src/html/logo.rs b/src/html/logo.rs index 0aafca55..2953849c 100644 --- a/src/html/logo.rs +++ b/src/html/logo.rs @@ -1,7 +1,5 @@ use crate::AutoDefault; -use crate::core::component::Context; -use crate::html::{Markup, html}; -use crate::locale::Lc; +use crate::html::{Markup, Props, html}; /// Representación SVG del **logotipo de PageTop** para incrustar en HTML. /// @@ -9,19 +7,19 @@ use crate::locale::Lc; /// /// ```rust,no_run /// # use pagetop::prelude::*; -/// fn render_logo(cx: &mut Context) -> Markup { +/// fn render_logo() -> Markup { /// html! { /// div class="logo_color" { -/// (PageTopSvg::Color.markup(cx)) +/// (PageTopSvg::Color.markup()) /// } /// div class="line_dark" { -/// (PageTopSvg::LineDark.markup(cx)) +/// (PageTopSvg::LineDark.markup()) /// } /// div class="line_light" { -/// (PageTopSvg::LineLight.markup(cx)) +/// (PageTopSvg::LineLight.markup()) /// } /// div class="line_red" { -/// (PageTopSvg::LineRGB(255, 0, 0).markup(cx)) +/// (PageTopSvg::LineRGB(255, 0, 0).markup()) /// } /// } /// }; @@ -42,29 +40,60 @@ pub enum PageTopSvg { impl PageTopSvg { /// Devuelve el marcado SVG del logotipo según la variante elegida. - pub fn markup(&self, cx: &Context) -> Markup { - let path_fills = match self { - Self::Color => self.logo_color(), - Self::LineDark => self.logo_line(10, 11, 9), - Self::LineLight => self.logo_line(255, 255, 255), - Self::LineRGB(r, g, b) => self.logo_line(*r, *g, *b), - }; + pub fn markup(&self) -> Markup { html! { svg viewBox="0 0 1614 1614" xmlns="http://www.w3.org/2000/svg" role="img" - aria-label=[Lc::l("pagetop_logo").lookup(cx)] + aria-label="PageTop" preserveAspectRatio="xMidYMid slice" focusable="false" { - (path_fills) + (self.path_fills()) + } + } + } + + /// Igual que [`markup()`], pero fusiona [`Props`] (identificador, clases, estilo, atributos) + /// directamente en el `` y deja la etiqueta libre para quien llama. Con `Some(texto)` se + /// muestra como imagen informativa (`role="img"` + `aria-label`), y con `None` como imagen + /// puramente decorativa (`aria-hidden="true"`, sin `role` ni `aria-label`). + /// + /// Pensado para poner el logotipo con clases, estilo y accesibilidad propios, sin envolverlo en + /// un elemento aparte; como hace el componente [`Image`] con [`image::Source::Logo`]. + /// + /// [`markup()`]: Self::markup + /// [`Image`]: crate::base::component::Image + /// [`image::Source::Logo`]: crate::base::component::image::Source::Logo + pub fn markup_with(&self, props: &Props, label: Option<&str>) -> Markup { + html! { + svg + viewBox="0 0 1614 1614" + xmlns="http://www.w3.org/2000/svg" + role=[label.is_some().then_some("img")] + aria-label=[label] + aria-hidden=[label.is_none().then_some("true")] + preserveAspectRatio="xMidYMid slice" + focusable="false" + (props) + { + (self.path_fills()) } } } // **< PageTopSvg HELPERS >********************************************************************* + fn path_fills(&self) -> Markup { + match self { + Self::Color => self.logo_color(), + Self::LineDark => self.logo_line(10, 11, 9), + Self::LineLight => self.logo_line(255, 255, 255), + Self::LineRGB(r, g, b) => self.logo_line(*r, *g, *b), + } + } + fn logo_color(&self) -> Markup { html! { path fill="rgb(255,184,75)" d="M 633,61 L 633,61 C 579,61 527,75 480,102 433,129 395,167 368,214 341,261 327,313 327,367 L 327,1244 327,1245 C 327,1299 341,1351 368,1398 395,1445 433,1483 480,1510 527,1537 579,1551 633,1551 L 982,1550 982,1551 C 1036,1551 1088,1537 1135,1510 1182,1483 1220,1445 1247,1398 1274,1351 1288,1299 1288,1245 L 1288,367 1288,367 1288,367 C 1288,313 1274,261 1247,214 1220,167 1182,129 1135,102 1088,75 1036,61 982,61 L 633,61 Z" {} diff --git a/src/locale/en-US/theme.ftl b/src/locale/en-US/theme.ftl index 3f4c0064..885eb841 100644 --- a/src/locale/en-US/theme.ftl +++ b/src/locale/en-US/theme.ftl @@ -2,9 +2,7 @@ region_header = Header region_content = Content region_footer = Footer - -# Logo. -pagetop_logo = PageTop Logo +region_aside = Aside # Error Messages. error_code = Error { $code } diff --git a/src/locale/es-ES/theme.ftl b/src/locale/es-ES/theme.ftl index 7d4abcf6..d77ee3c9 100644 --- a/src/locale/es-ES/theme.ftl +++ b/src/locale/es-ES/theme.ftl @@ -2,9 +2,7 @@ region_header = Cabecera region_content = Contenido region_footer = Pie de página - -# Logo. -pagetop_logo = Logotipo de PageTop +region_aside = Barra lateral # Error Messages. error_code = Error { $code } diff --git a/tests/component_badge.rs b/tests/component_badge.rs index f148c023..2d039e3b 100644 --- a/tests/component_badge.rs +++ b/tests/component_badge.rs @@ -28,7 +28,7 @@ async fn renders_as_a_span_element() { } #[pagetop::test] -async fn default_kind_is_secondary() { +async fn default_intent_is_secondary() { let mut badge = Badge::labeled(Lc::n("Admin")); let html = badge.render(&mut Context::default()).await.into_string(); @@ -36,7 +36,7 @@ async fn default_kind_is_secondary() { } #[pagetop::test] -async fn each_direct_constructor_sets_its_kind() { +async fn each_direct_constructor_sets_its_intent() { let cases = [ (Badge::primary(Lc::n("x")), "badge-primary"), (Badge::secondary(Lc::n("x")), "badge-secondary"), @@ -55,17 +55,17 @@ async fn each_direct_constructor_sets_its_kind() { } #[pagetop::test] -async fn with_kind_overrides_the_default() { - let mut badge = Badge::labeled(Lc::n("Admin")).with_kind(BadgeKind::Danger); +async fn with_intent_overrides_the_default() { + let mut badge = Badge::labeled(Lc::n("Admin")).with_intent(Intent::Danger); let html = badge.render(&mut Context::default()).await.into_string(); assert!(html.contains(r#"class="badge badge-danger""#)); } #[pagetop::test] -async fn direct_constructor_is_equivalent_to_labeled_with_kind() { +async fn direct_constructor_is_equivalent_to_labeled_with_intent() { let mut from_constructor = Badge::danger(Lc::n("Admin")); - let mut from_builder = Badge::labeled(Lc::n("Admin")).with_kind(BadgeKind::Danger); + let mut from_builder = Badge::labeled(Lc::n("Admin")).with_intent(Intent::Danger); assert_eq!( from_constructor @@ -88,7 +88,7 @@ async fn with_id_sets_the_identifier() { } #[pagetop::test] -async fn with_prop_adds_extra_classes_alongside_the_kind_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 html = badge.render(&mut Context::default()).await.into_string();