♻️ (bootsier): Refactoriza la gestión de clases

- Mejora la legibilidad del código.
- Simplifica las alteraciones de clases en los componentes `Container`,
  `Dropdown`, `Image`, `Nav`, `Navbar` y `Offcanvas` usando métodos
  dedicados para generar clases en función de sus propiedades.
- Mejora los enums añadiendo métodos que devuelven sus clases
  asociadas, reduciendo código repetitivo.
- Elimina el trait `JoinClasses` y su implementación, integrando la
  lógica de unión de clases directamente en los componentes.
This commit is contained in:
Manuel Cillero 2025-11-15 13:16:15 +01:00
parent 748bd81bf1
commit 2e39af0856
33 changed files with 1607 additions and 647 deletions

View file

@ -2,12 +2,10 @@ use pagetop::prelude::*;
use crate::theme::aux::Color;
use std::fmt;
// **< ButtonColor >********************************************************************************
/// Variantes de color `btn-*` para botones.
#[derive(AutoDefault)]
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
pub enum ButtonColor {
/// No define ninguna clase.
#[default]
@ -20,14 +18,72 @@ pub enum ButtonColor {
Link,
}
#[rustfmt::skip]
impl fmt::Display for ButtonColor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl ButtonColor {
const BTN_PREFIX: &str = "btn-";
const BTN_OUTLINE_PREFIX: &str = "btn-outline-";
const BTN_LINK: &str = "btn-link";
// Añade la clase `btn-*` a la cadena de clases.
#[inline]
pub(crate) fn push_class(self, classes: &mut String) {
if let Self::Default = self {
return;
}
if !classes.is_empty() {
classes.push(' ');
}
match self {
Self::Default => Ok(()),
Self::Background(c) => write!(f, "btn-{c}"),
Self::Outline(c) => write!(f, "btn-outline-{c}"),
Self::Link => f.write_str("btn-link"),
Self::Default => unreachable!(),
Self::Background(c) => {
classes.push_str(Self::BTN_PREFIX);
classes.push_str(c.as_str());
}
Self::Outline(c) => {
classes.push_str(Self::BTN_OUTLINE_PREFIX);
classes.push_str(c.as_str());
}
Self::Link => {
classes.push_str(Self::BTN_LINK);
}
}
}
/// Devuelve la clase `btn-*` correspondiente al color del botón.
///
/// # Ejemplos
///
/// ```rust
/// # use pagetop_bootsier::prelude::*;
/// assert_eq!(
/// ButtonColor::Background(Color::Primary).to_class(),
/// "btn-primary"
/// );
/// assert_eq!(
/// ButtonColor::Outline(Color::Danger).to_class(),
/// "btn-outline-danger"
/// );
/// assert_eq!(ButtonColor::Link.to_class(), "btn-link");
/// assert_eq!(ButtonColor::Default.to_class(), "");
/// ```
#[inline]
pub fn to_class(self) -> String {
match self {
Self::Default => String::new(),
Self::Background(c) => {
let color = c.as_str();
let mut class = String::with_capacity(Self::BTN_PREFIX.len() + color.len());
class.push_str(Self::BTN_PREFIX);
class.push_str(color);
class
}
Self::Outline(c) => {
let color = c.as_str();
let mut class = String::with_capacity(Self::BTN_OUTLINE_PREFIX.len() + color.len());
class.push_str(Self::BTN_OUTLINE_PREFIX);
class.push_str(color);
class
}
Self::Link => Self::BTN_LINK.to_string(),
}
}
}
@ -35,7 +91,7 @@ impl fmt::Display for ButtonColor {
// **< ButtonSize >*********************************************************************************
/// Tamaño visual de un botón.
#[derive(AutoDefault)]
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
pub enum ButtonSize {
/// Tamaño por defecto del tema (no añade clase).
#[default]
@ -46,13 +102,42 @@ pub enum ButtonSize {
Large,
}
#[rustfmt::skip]
impl fmt::Display for ButtonSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl ButtonSize {
const BTN_SM: &str = "btn-sm";
const BTN_LG: &str = "btn-lg";
// Añade la clase de tamaño `btn-sm` o `btn-lg` a la cadena de clases.
#[inline]
pub(crate) fn push_class(self, classes: &mut String) {
if let Self::Default = self {
return;
}
if !classes.is_empty() {
classes.push(' ');
}
match self {
Self::Default => Ok(()),
Self::Small => f.write_str("btn-sm"),
Self::Large => f.write_str("btn-lg"),
Self::Default => unreachable!(),
Self::Small => classes.push_str(Self::BTN_SM),
Self::Large => classes.push_str(Self::BTN_LG),
}
}
/// Devuelve la clase `btn-sm` o `btn-lg` correspondiente al tamaño del botón.
///
/// # Ejemplos
///
/// ```rust
/// # use pagetop_bootsier::prelude::*;
/// assert_eq!(ButtonSize::Small.to_class(), "btn-sm");
/// assert_eq!(ButtonSize::Large.to_class(), "btn-lg");
/// assert_eq!(ButtonSize::Default.to_class(), "");
/// ```
#[inline]
pub fn to_class(self) -> String {
match self {
Self::Default => String::new(),
Self::Small => Self::BTN_SM.to_string(),
Self::Large => Self::BTN_LG.to_string(),
}
}
}