✨ Añade clases de fondo, texto, bordes y esquinas
- Refactoriza el componente contenedor `Container` para usar estas clases y aplicar los nuevos enums `Kind` y `Width` para mejorar el comportamiento semántico y *responsive*. - Actualiza los componentes `Dropdown`, `Image`, `Nav`, `Navbar` y `Offcanvas` para usar los nuevos métodos de unión de clases. - Elimina propiedades de estilo redundantes de los componentes `Navbar` e `Image`, simplificando sus interfaces.
This commit is contained in:
parent
5ec69345b3
commit
748bd81bf1
23 changed files with 1041 additions and 994 deletions
|
|
@ -1,16 +1,47 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::theme::aux::Color;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
// **< BorderColor >********************************************************************************
|
||||
|
||||
/// Colores `border-*` para los bordes ([`classes::Border`](crate::theme::classes::Border)).
|
||||
#[derive(AutoDefault)]
|
||||
pub enum BorderColor {
|
||||
/// No define ninguna clase.
|
||||
#[default]
|
||||
Default,
|
||||
/// Genera internamente clases `border-{color}`.
|
||||
Theme(Color),
|
||||
/// Genera internamente clases `border-{color}-subtle` (un tono suavizado del color).
|
||||
Subtle(Color),
|
||||
/// Color negro.
|
||||
Black,
|
||||
/// Color blanco.
|
||||
White,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for BorderColor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Default => Ok(()),
|
||||
Self::Theme(c) => write!(f, "border-{c}"),
|
||||
Self::Subtle(c) => write!(f, "border-{c}-subtle"),
|
||||
Self::Black => f.write_str("border-black"),
|
||||
Self::White => f.write_str("border-white"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **< BorderSize >*********************************************************************************
|
||||
|
||||
/// Tamaño para el ancho de los bordes ([`Border`]).
|
||||
/// Tamaño para el ancho de los bordes ([`classes::Border`](crate::theme::classes::Border)).
|
||||
///
|
||||
/// Mapea a `border`, `border-0` y `border-{1..5}`:
|
||||
///
|
||||
/// - `None` no añade clase (devuelve `""`).
|
||||
/// - `None` no añade ninguna clase.
|
||||
/// - `Default` genera `border` (borde por defecto del tema).
|
||||
/// - `Zero` genera `border-0` (sin borde).
|
||||
/// - `Scale{1..5}` genera `border-{1..5}` (ancho creciente).
|
||||
|
|
@ -29,7 +60,7 @@ pub enum BorderSize {
|
|||
|
||||
impl BorderSize {
|
||||
#[rustfmt::skip]
|
||||
fn to_class(&self, prefix: impl AsRef<str>) -> String {
|
||||
pub(crate) fn to_class(&self, prefix: impl AsRef<str>) -> String {
|
||||
match self {
|
||||
Self::None => String::new(),
|
||||
Self::Default => String::from(prefix.as_ref()),
|
||||
|
|
@ -48,146 +79,3 @@ impl fmt::Display for BorderSize {
|
|||
write!(f, "{}", self.to_class("border"))
|
||||
}
|
||||
}
|
||||
|
||||
// **< Border >*************************************************************************************
|
||||
|
||||
/// Agrupa propiedades para crear **bordes**.
|
||||
///
|
||||
/// Permite:
|
||||
///
|
||||
/// - Definir un tamaño **global** para todo el borde (`size`).
|
||||
/// - Ajustar el tamaño de cada **lado lógico** (`top`, `end`, `bottom`, `start`, **en este orden**,
|
||||
/// respetando LTR/RTL).
|
||||
/// - Aplicar un **color** al borde (`ColorBorder`).
|
||||
/// - Aplicar un nivel de **opacidad** (`BorderOpacity`).
|
||||
///
|
||||
/// # Comportamiento aditivo / sustractivo
|
||||
///
|
||||
/// - **Aditivo**: basta con crear un borde sin tamaño con `Border::new()` para ir añadiendo cada
|
||||
/// lado lógico con el tamaño deseado usando `BorderSize::Scale{1..5}`.
|
||||
///
|
||||
/// - **Sustractivo**: se crea un borde con tamaño predefinido, p. ej. utilizando
|
||||
/// `Border::with(BorderSize::Scale2)` y eliminar los lados deseados con `BorderSize::Zero`.
|
||||
///
|
||||
/// - **Anchos diferentes por lado**: usando `BorderSize::Scale{1..5}` en cada lado deseado.
|
||||
///
|
||||
/// # Ejemplos
|
||||
///
|
||||
/// **Borde global:**
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let b = Border::with(BorderSize::Scale2);
|
||||
/// assert_eq!(b.to_string(), "border-2");
|
||||
/// ```
|
||||
///
|
||||
/// **Aditivo (solo borde superior):**
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let b = Border::new().with_top(BorderSize::Scale1);
|
||||
/// assert_eq!(b.to_string(), "border-top-1");
|
||||
/// ```
|
||||
///
|
||||
/// **Sustractivo (borde global menos el superior):**
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let b = Border::with(BorderSize::Default).with_top(BorderSize::Zero);
|
||||
/// assert_eq!(b.to_string(), "border border-top-0");
|
||||
/// ```
|
||||
///
|
||||
/// **Ancho por lado (lado lógico inicial a 2 y final a 4):**
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let b = Border::new().with_start(BorderSize::Scale2).with_end(BorderSize::Scale4);
|
||||
/// assert_eq!(b.to_string(), "border-end-4 border-start-2");
|
||||
/// ```
|
||||
///
|
||||
/// **Combinado (ejemplo completo):**
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let b = Border::with(BorderSize::Default) // Borde global por defecto.
|
||||
/// .with_top(BorderSize::Zero) // Quita borde superior.
|
||||
/// .with_end(BorderSize::Scale3) // Ancho 3 para el lado lógico final.
|
||||
/// .with_style(StyleBorder::Both(ColorBorder::Theme(Color::Primary), Opacity::Half));
|
||||
///
|
||||
/// assert_eq!(b.to_string(), "border border-top-0 border-end-3 border-primary border-opacity-50");
|
||||
/// ```
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Border {
|
||||
size : BorderSize,
|
||||
top : BorderSize,
|
||||
end : BorderSize,
|
||||
bottom: BorderSize,
|
||||
start : BorderSize,
|
||||
style : StyleBorder,
|
||||
}
|
||||
|
||||
impl Border {
|
||||
/// Prepara un borde **sin tamaño global** de partida.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Crea un borde **con tamaño global** (`size`).
|
||||
pub fn with(size: BorderSize) -> Self {
|
||||
Self::default().with_size(size)
|
||||
}
|
||||
|
||||
// **< Border BUILDER >*************************************************************************
|
||||
|
||||
/// Establece el tamaño global del borde (`border*`).
|
||||
pub fn with_size(mut self, size: BorderSize) -> Self {
|
||||
self.size = size;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el tamaño del borde superior (`border-top-*`).
|
||||
pub fn with_top(mut self, size: BorderSize) -> Self {
|
||||
self.top = size;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el tamaño del borde en el lado lógico final (`border-end-*`). Respeta LTR/RTL.
|
||||
pub fn with_end(mut self, size: BorderSize) -> Self {
|
||||
self.end = size;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el tamaño del borde inferior (`border-bottom-*`).
|
||||
pub fn with_bottom(mut self, size: BorderSize) -> Self {
|
||||
self.bottom = size;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el tamaño del borde en el lado lógico inicial (`border-start-*`). Respeta LTR/RTL.
|
||||
pub fn with_start(mut self, size: BorderSize) -> Self {
|
||||
self.start = size;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el estilo de color/opacidad del borde.
|
||||
pub fn with_style(mut self, style: StyleBorder) -> Self {
|
||||
self.style = style;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Border {
|
||||
/// Concatena cada definición en el orden: *global*, `top`, `end`, `bottom`, `start` y
|
||||
/// *color*/*opacidad*; respetando LTR/RTL y omitiendo las definiciones vacías.
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
join_opt!([
|
||||
self.size.to_string(),
|
||||
self.top.to_class("border-top"),
|
||||
self.end.to_class("border-end"),
|
||||
self.bottom.to_class("border-bottom"),
|
||||
self.start.to_class("border-start"),
|
||||
self.style.to_string(),
|
||||
]; " ")
|
||||
.unwrap_or_default()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,25 +3,6 @@ use pagetop::prelude::*;
|
|||
use std::fmt;
|
||||
|
||||
/// Define los puntos de ruptura (*breakpoints*) para aplicar diseño *responsive*.
|
||||
///
|
||||
/// - `"sm"`, `"md"`, `"lg"`, `"xl"` o `"xxl"` para los puntos de ruptura `SM`, `MD`, `LG`, `XL` o
|
||||
/// `XXL`, respectivamente.
|
||||
/// - `""` (cadena vacía) para `None`.
|
||||
///
|
||||
/// # Ejemplos
|
||||
///
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// assert_eq!(BreakPoint::MD.to_string(), "md");
|
||||
/// assert_eq!(BreakPoint::None.to_string(), "");
|
||||
///
|
||||
/// // Forma correcta para clases con prefijo:
|
||||
/// assert_eq!(BreakPoint::MD.to_class("col"), "col-md");
|
||||
/// assert_eq!(BreakPoint::None.to_class("offcanvas"), "offcanvas");
|
||||
///
|
||||
/// assert_eq!(BreakPoint::XXL.try_class("col"), Some("col-xxl".to_string()));
|
||||
/// assert_eq!(BreakPoint::None.try_class("offcanvas"), None);
|
||||
/// ```
|
||||
#[derive(AutoDefault)]
|
||||
pub enum BreakPoint {
|
||||
/// **Menos de 576px**. Dispositivos muy pequeños: teléfonos en modo vertical.
|
||||
|
|
@ -40,46 +21,43 @@ pub enum BreakPoint {
|
|||
}
|
||||
|
||||
impl BreakPoint {
|
||||
/// Comprueba si es un punto de ruptura efectivo.
|
||||
///
|
||||
/// Devuelve `true` si el valor es `SM`, `MD`, `LG`, `XL` o `XXL`; y `false` en otro caso.
|
||||
#[rustfmt::skip]
|
||||
#[inline]
|
||||
pub const fn is_breakpoint(&self) -> bool {
|
||||
!matches!(self, Self::None)
|
||||
const fn suffix(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::None => None,
|
||||
Self::SM => Some("sm"),
|
||||
Self::MD => Some("md"),
|
||||
Self::LG => Some("lg"),
|
||||
Self::XL => Some("xl"),
|
||||
Self::XXL => Some("xxl"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Genera un nombre de clase CSS basado en el punto de ruptura.
|
||||
///
|
||||
/// Si es un punto de ruptura efectivo (ver [`is_breakpoint()`](Self::is_breakpoint), concatena
|
||||
/// el prefijo, un guion (`-`) y el sufijo asociado. En otro caso devuelve únicamente el
|
||||
/// prefijo.
|
||||
/// Si es un punto de ruptura efectivo concatena el prefijo, un guion (`-`) y el sufijo
|
||||
/// asociado. Para `None` devuelve sólo el prefijo.
|
||||
///
|
||||
/// # Ejemplo
|
||||
///
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let breakpoint = BreakPoint::MD;
|
||||
/// let class = breakpoint.to_class("col");
|
||||
/// assert_eq!(class, "col-md".to_string());
|
||||
/// assert_eq!(breakpoint.to_class("col"), "col-md");
|
||||
///
|
||||
/// let breakpoint = BreakPoint::None;
|
||||
/// let class = breakpoint.to_class("offcanvas");
|
||||
/// assert_eq!(class, "offcanvas".to_string());
|
||||
/// assert_eq!(breakpoint.to_class("offcanvas"), "offcanvas");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_class(&self, prefix: impl AsRef<str>) -> String {
|
||||
if self.is_breakpoint() {
|
||||
join!(prefix, "-", self.to_string())
|
||||
} else {
|
||||
String::from(prefix.as_ref())
|
||||
}
|
||||
join_pair!(prefix, "-", self.suffix().unwrap_or_default())
|
||||
}
|
||||
|
||||
/// Intenta generar un nombre de clase CSS basado en el punto de ruptura.
|
||||
///
|
||||
/// Si es un punto de ruptura efectivo (ver [`is_breakpoint()`](Self::is_breakpoint), devuelve
|
||||
/// `Some(String)` concatenando el prefijo, un guion (`-`) y el sufijo asociado. En otro caso
|
||||
/// devuelve `None`.
|
||||
/// Si es un punto de ruptura efectivo devuelve `Some(String)` concatenando el prefijo, un guion
|
||||
/// (`-`) y el sufijo asociado. En otro caso devuelve `None`.
|
||||
///
|
||||
/// # Ejemplo
|
||||
///
|
||||
|
|
@ -95,24 +73,19 @@ impl BreakPoint {
|
|||
/// ```
|
||||
#[inline]
|
||||
pub fn try_class(&self, prefix: impl AsRef<str>) -> Option<String> {
|
||||
if self.is_breakpoint() {
|
||||
Some(join!(prefix, "-", self.to_string()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
self.suffix().map(|suffix| join_pair!(prefix, "-", suffix))
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for BreakPoint {
|
||||
/// Implementa [`Display`](std::fmt::Display) para asociar `"sm"`, `"md"`, `"lg"`, `"xl"` o
|
||||
/// `"xxl"` a los puntos de ruptura `BreakPoint::SM`, `MD`, `LG`, `XL` o `XXL`, respectivamente.
|
||||
/// Y `""` (cadena vacía) a `BreakPoint::None`.
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::None => Ok(()),
|
||||
Self::SM => f.write_str("sm"),
|
||||
Self::MD => f.write_str("md"),
|
||||
Self::LG => f.write_str("lg"),
|
||||
Self::XL => f.write_str("xl"),
|
||||
Self::XXL => f.write_str("xxl"),
|
||||
if let Some(suffix) = self.suffix() {
|
||||
f.write_str(suffix)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
58
extensions/pagetop-bootsier/src/theme/aux/button.rs
Normal file
58
extensions/pagetop-bootsier/src/theme/aux/button.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::theme::aux::Color;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
// **< ButtonColor >********************************************************************************
|
||||
|
||||
/// Variantes de color `btn-*` para botones.
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ButtonColor {
|
||||
/// No define ninguna clase.
|
||||
#[default]
|
||||
Default,
|
||||
/// Genera internamente clases `btn-{color}` (botón relleno).
|
||||
Background(Color),
|
||||
/// Genera `btn-outline-{color}` (fondo transparente y contorno con borde).
|
||||
Outline(Color),
|
||||
/// Aplica estilo de los enlaces (`btn-link`), sin caja ni fondo, heredando el color de texto.
|
||||
Link,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for ButtonColor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **< ButtonSize >*********************************************************************************
|
||||
|
||||
/// Tamaño visual de un botón.
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ButtonSize {
|
||||
/// Tamaño por defecto del tema (no añade clase).
|
||||
#[default]
|
||||
Default,
|
||||
/// Botón compacto.
|
||||
Small,
|
||||
/// Botón destacado/grande.
|
||||
Large,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for ButtonSize {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Default => Ok(()),
|
||||
Self::Small => f.write_str("btn-sm"),
|
||||
Self::Large => f.write_str("btn-lg"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,10 @@ use std::fmt;
|
|||
/// Paleta de colores temáticos.
|
||||
///
|
||||
/// Equivalen a los nombres estándar definidos por Bootstrap (`primary`, `secondary`, `success`,
|
||||
/// etc.). Este tipo enumerado sirve de base para componer clases de color para el fondo
|
||||
/// ([`ColorBg`]), bordes ([`ColorBorder`]) y texto ([`ColorText`]).
|
||||
/// etc.). Este tipo enumerado sirve de base para componer las clases de color para fondo
|
||||
/// ([`classes::Background`](crate::theme::classes::Background)), bordes
|
||||
/// ([`classes::Border`](crate::theme::classes::Border)) y texto
|
||||
/// ([`classes::Text`](crate::theme::classes::Text)).
|
||||
#[derive(AutoDefault)]
|
||||
pub enum Color {
|
||||
#[default]
|
||||
|
|
@ -38,12 +40,69 @@ impl fmt::Display for Color {
|
|||
}
|
||||
}
|
||||
|
||||
// **< Opacity >************************************************************************************
|
||||
|
||||
/// Niveles de opacidad (`opacity-*`).
|
||||
///
|
||||
/// Se usa normalmente para graduar la transparencia del color de fondo `bg-opacity-*`
|
||||
/// ([`classes::Background`](crate::theme::classes::Background)), de los bordes `border-opacity-*`
|
||||
/// ([`classes::Border`](crate::theme::classes::Border)) o del texto `text-opacity-*`
|
||||
/// ([`classes::Text`](crate::theme::classes::Text)).
|
||||
#[derive(AutoDefault)]
|
||||
pub enum Opacity {
|
||||
/// No define ninguna clase.
|
||||
#[default]
|
||||
Default,
|
||||
/// Permite generar clases `*-opacity-100` (100% de opacidad).
|
||||
Opaque,
|
||||
/// Permite generar clases `*-opacity-75` (75%).
|
||||
SemiOpaque,
|
||||
/// Permite generar clases `*-opacity-50` (50%).
|
||||
Half,
|
||||
/// Permite generar clases `*-opacity-25` (25%).
|
||||
SemiTransparent,
|
||||
/// Permite generar clases `*-opacity-10` (10%).
|
||||
AlmostTransparent,
|
||||
/// Permite generar clases `*-opacity-0` (0%, totalmente transparente).
|
||||
Transparent,
|
||||
}
|
||||
|
||||
impl Opacity {
|
||||
#[rustfmt::skip]
|
||||
#[inline]
|
||||
const fn suffix(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Default => "",
|
||||
Self::Opaque => "opacity-100",
|
||||
Self::SemiOpaque => "opacity-75",
|
||||
Self::Half => "opacity-50",
|
||||
Self::SemiTransparent => "opacity-25",
|
||||
Self::AlmostTransparent => "opacity-10",
|
||||
Self::Transparent => "opacity-0",
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_class(&self, prefix: impl AsRef<str>) -> String {
|
||||
match self {
|
||||
Self::Default => String::new(),
|
||||
_ => join_pair!(prefix, "-", self.suffix()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Opacity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self.suffix())
|
||||
}
|
||||
}
|
||||
|
||||
// **< ColorBg >************************************************************************************
|
||||
|
||||
/// Colores `bg-*` para el fondo.
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ColorBg {
|
||||
/// No define ninguna clase (devuelve `""` para facilitar la composición de clases).
|
||||
/// No define ninguna clase.
|
||||
#[default]
|
||||
Default,
|
||||
/// Fondo predefinido del tema (`bg-body`).
|
||||
|
|
@ -81,71 +140,12 @@ impl fmt::Display for ColorBg {
|
|||
}
|
||||
}
|
||||
|
||||
// **< ColorBorder >********************************************************************************
|
||||
|
||||
/// Colores `border-*` para los bordes ([`Border`](crate::theme::aux::Border)).
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ColorBorder {
|
||||
/// No define ninguna clase (devuelve `""` para facilitar la composición de clases).
|
||||
#[default]
|
||||
Default,
|
||||
/// Genera internamente clases `border-{color}`.
|
||||
Theme(Color),
|
||||
/// Genera internamente clases `border-{color}-subtle` (un tono suavizado del color).
|
||||
Subtle(Color),
|
||||
/// Color negro.
|
||||
Black,
|
||||
/// Color blanco.
|
||||
White,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for ColorBorder {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Default => Ok(()),
|
||||
Self::Theme(c) => write!(f, "border-{c}"),
|
||||
Self::Subtle(c) => write!(f, "border-{c}-subtle"),
|
||||
Self::Black => f.write_str("border-black"),
|
||||
Self::White => f.write_str("border-white"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **< ColorButton >********************************************************************************
|
||||
|
||||
/// Variantes de color `btn-*` para botones.
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ColorButton {
|
||||
/// No define ninguna clase (devuelve `""` para facilitar la composición de clases).
|
||||
#[default]
|
||||
Default,
|
||||
/// Genera internamente clases `btn-{color}` (botón relleno).
|
||||
Background(Color),
|
||||
/// Genera `btn-outline-{color}` (fondo transparente y contorno con borde).
|
||||
Outline(Color),
|
||||
/// Aplica estilo de los enlaces (`btn-link`), sin caja ni fondo, heredando el color de texto.
|
||||
Link,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for ColorButton {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **< ColorText >**********************************************************************************
|
||||
|
||||
/// Colores `text-*` para el texto.
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ColorText {
|
||||
/// No define ninguna clase (devuelve `""` para facilitar la composición de clases).
|
||||
/// No define ninguna clase.
|
||||
#[default]
|
||||
Default,
|
||||
/// Color predefinido del tema (`text-body`).
|
||||
|
|
@ -182,135 +182,3 @@ impl fmt::Display for ColorText {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **< Opacity >************************************************************************************
|
||||
|
||||
/// Niveles de opacidad (`opacity-*`).
|
||||
///
|
||||
/// Se usa normalmente para graduar la transparencia del color de fondo `bg-opacity-*`
|
||||
/// ([`StyleBg`]), de los bordes `border-opacity-*` ([`StyleBorder`]) o del texto `text-opacity-*`
|
||||
/// ([`StyleText`]).
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub enum Opacity {
|
||||
/// Genera internamente clases `opacity-100` (100% de opacidad).
|
||||
#[default]
|
||||
Opaque,
|
||||
/// Genera internamente clases `opacity-75` (75%).
|
||||
SemiOpaque,
|
||||
/// Genera internamente clases `opacity-50` (50%).
|
||||
Half,
|
||||
/// Genera internamente clases `opacity-25` (25%).
|
||||
SemiTransparent,
|
||||
/// Genera internamente clases `opacity-10` (10%).
|
||||
AlmostTransparent,
|
||||
/// Genera internamente clases `opacity-0` (0%, totalmente transparente).
|
||||
Transparent,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for Opacity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Opaque => f.write_str("opacity-100"),
|
||||
Self::SemiOpaque => f.write_str("opacity-75"),
|
||||
Self::Half => f.write_str("opacity-50"),
|
||||
Self::SemiTransparent => f.write_str("opacity-25"),
|
||||
Self::AlmostTransparent => f.write_str("opacity-10"),
|
||||
Self::Transparent => f.write_str("opacity-0"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **< StyleBg >***********************************************************************************
|
||||
|
||||
/// Estilos de color/opacidad para el fondo.
|
||||
#[derive(AutoDefault)]
|
||||
pub enum StyleBg {
|
||||
/// No define ninguna clase (devuelve `""` para facilitar la composición de clases).
|
||||
#[default]
|
||||
Default,
|
||||
/// Genera internamente clases `bg-*`.
|
||||
Color(ColorBg),
|
||||
/// Genera internamente clases `bg-opacity-*`.
|
||||
Opacity(Opacity),
|
||||
/// Genera internamente clases `bg-* bg-opacity-*`.
|
||||
Both(ColorBg, Opacity),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for StyleBg {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Default => Ok(()),
|
||||
Self::Color(c) => write!(f, "{c}"),
|
||||
Self::Opacity(o) => write!(f, "bg-{o}"),
|
||||
Self::Both(c, o) => write!(f, "{c} bg-{o}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **< StyleBorder >*******************************************************************************
|
||||
|
||||
/// Estilos de color/opacidad para los bordes ([`Border`](crate::theme::aux::Border)).
|
||||
#[derive(AutoDefault)]
|
||||
pub enum StyleBorder {
|
||||
/// No define ninguna clase (devuelve `""` para facilitar la composición de clases).
|
||||
#[default]
|
||||
Default,
|
||||
/// Genera internamente clases `border-*`.
|
||||
Color(ColorBorder),
|
||||
/// Genera internamente clases `border-opacity-*`.
|
||||
Opacity(Opacity),
|
||||
/// Genera internamente clases `border-* border-opacity-*`.
|
||||
Both(ColorBorder, Opacity),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for StyleBorder {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Default => Ok(()),
|
||||
Self::Color(c) => write!(f, "{c}"),
|
||||
Self::Opacity(o) => write!(f, "border-{o}"),
|
||||
Self::Both(c, o) => write!(f, "{c} border-{o}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **< StyleText >*********************************************************************************
|
||||
|
||||
/// Estilos de color/opacidad para texto y fondo del texto.
|
||||
#[derive(AutoDefault)]
|
||||
pub enum StyleText {
|
||||
/// No define ninguna clase (devuelve `""` para facilitar la composición de clases).
|
||||
#[default]
|
||||
Default,
|
||||
/// Genera internamente clases `text-*`.
|
||||
Color(ColorText),
|
||||
/// Genera internamente clases `text-opacity-*`.
|
||||
Opacity(Opacity),
|
||||
/// Genera internamente clases `text-* text-opacity-*`.
|
||||
Both(ColorText, Opacity),
|
||||
/// Genera internamente clases `text-bg-*` (para el color de fondo del texto).
|
||||
Bg(Color),
|
||||
/// Genera internamente clases `text-bg-* text-*`.
|
||||
BgAndColor(Color, ColorText),
|
||||
/// Genera internamente clases `text-bg-* text-* text-opacity-*`.
|
||||
All(Color, ColorText, Opacity),
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for StyleText {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Default => Ok(()),
|
||||
Self::Color(c) => write!(f, "{c}"),
|
||||
Self::Opacity(o) => write!(f, "text-{o}"),
|
||||
Self::Both(c, o) => write!(f, "{c} text-{o}"),
|
||||
Self::Bg(bg) => write!(f, "text-bg-{bg}"),
|
||||
Self::BgAndColor(bg, c) => write!(f, "text-bg-{bg} {c}"),
|
||||
Self::All(bg, c, o) => write!(f, "text-bg-{bg} {c} text-{o}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,11 @@ use pagetop::prelude::*;
|
|||
|
||||
use std::fmt;
|
||||
|
||||
// **< RoundedRadius >******************************************************************************
|
||||
|
||||
/// Radio para el redondeo de esquinas ([`Rounded`]).
|
||||
/// Radio para el redondeo de esquinas ([`classes::Rounded`](crate::theme::classes::Rounded)).
|
||||
///
|
||||
/// Mapea a `rounded`, `rounded-0`, `rounded-{1..5}`, `rounded-circle` y `rounded-pill`.
|
||||
///
|
||||
/// - `None` no añade clase (devuelve `""`).
|
||||
/// - `None` no añade ninguna clase.
|
||||
/// - `Default` genera `rounded` (radio por defecto del tema).
|
||||
/// - `Zero` genera `rounded-0` (sin redondeo).
|
||||
/// - `Scale{1..5}` genera `rounded-{1..5}` (radio creciente).
|
||||
|
|
@ -31,18 +29,18 @@ pub enum RoundedRadius {
|
|||
|
||||
impl RoundedRadius {
|
||||
#[rustfmt::skip]
|
||||
fn to_class(&self, base: impl AsRef<str>) -> String {
|
||||
pub(crate) fn to_class(&self, prefix: impl AsRef<str>) -> String {
|
||||
match self {
|
||||
RoundedRadius::None => String::new(),
|
||||
RoundedRadius::Default => String::from(base.as_ref()),
|
||||
RoundedRadius::Zero => join!(base, "-0"),
|
||||
RoundedRadius::Scale1 => join!(base, "-1"),
|
||||
RoundedRadius::Scale2 => join!(base, "-2"),
|
||||
RoundedRadius::Scale3 => join!(base, "-3"),
|
||||
RoundedRadius::Scale4 => join!(base, "-4"),
|
||||
RoundedRadius::Scale5 => join!(base, "-5"),
|
||||
RoundedRadius::Circle => join!(base, "-circle"),
|
||||
RoundedRadius::Pill => join!(base, "-pill"),
|
||||
RoundedRadius::Default => String::from(prefix.as_ref()),
|
||||
RoundedRadius::Zero => join!(prefix, "-0"),
|
||||
RoundedRadius::Scale1 => join!(prefix, "-1"),
|
||||
RoundedRadius::Scale2 => join!(prefix, "-2"),
|
||||
RoundedRadius::Scale3 => join!(prefix, "-3"),
|
||||
RoundedRadius::Scale4 => join!(prefix, "-4"),
|
||||
RoundedRadius::Scale5 => join!(prefix, "-5"),
|
||||
RoundedRadius::Circle => join!(prefix, "-circle"),
|
||||
RoundedRadius::Pill => join!(prefix, "-pill"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -52,163 +50,3 @@ impl fmt::Display for RoundedRadius {
|
|||
write!(f, "{}", self.to_class("rounded"))
|
||||
}
|
||||
}
|
||||
|
||||
// **< Rounded >************************************************************************************
|
||||
|
||||
/// Agrupa propiedades para crear **esquinas redondeadas**.
|
||||
///
|
||||
/// Permite:
|
||||
///
|
||||
/// - Definir un radio **global para todas las esquinas** (`radius`).
|
||||
/// - Ajustar el radio asociado a las **esquinas de cada lado lógico** (`top`, `end`, `bottom`,
|
||||
/// `start`, **en este orden**, respetando LTR/RTL).
|
||||
/// - Ajustar el radio de las **esquinas concretas** (`top-start`, `top-end`, `bottom-start`,
|
||||
/// `bottom-end`, **en este orden**, respetando LTR/RTL).
|
||||
///
|
||||
/// # Ejemplos
|
||||
///
|
||||
/// **Radio global:**
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let r = Rounded::with(RoundedRadius::Default);
|
||||
/// assert_eq!(r.to_string(), "rounded");
|
||||
/// ```
|
||||
///
|
||||
/// **Sin redondeo:**
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let r = Rounded::new();
|
||||
/// assert_eq!(r.to_string(), "");
|
||||
/// ```
|
||||
///
|
||||
/// **Radio en las esquinas de un lado lógico:**
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let r = Rounded::new().with_end(RoundedRadius::Scale2);
|
||||
/// assert_eq!(r.to_string(), "rounded-end-2");
|
||||
/// ```
|
||||
///
|
||||
/// **Radio en una esquina concreta:**
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let r = Rounded::new().with_top_start(RoundedRadius::Scale3);
|
||||
/// assert_eq!(r.to_string(), "rounded-top-start-3");
|
||||
/// ```
|
||||
///
|
||||
/// **Combinado (ejemplo completo):**
|
||||
/// ```rust
|
||||
/// # use pagetop_bootsier::prelude::*;
|
||||
/// let r = Rounded::new()
|
||||
/// .with_top(RoundedRadius::Default) // Añade redondeo arriba.
|
||||
/// .with_bottom_start(RoundedRadius::Scale4) // Añade una esquina redondeada concreta.
|
||||
/// .with_bottom_end(RoundedRadius::Circle); // Añade redondeo extremo en otra esquina.
|
||||
///
|
||||
/// assert_eq!(r.to_string(), "rounded-top rounded-bottom-start-4 rounded-bottom-end-circle");
|
||||
/// ```
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Rounded {
|
||||
radius : RoundedRadius,
|
||||
top : RoundedRadius,
|
||||
end : RoundedRadius,
|
||||
bottom : RoundedRadius,
|
||||
start : RoundedRadius,
|
||||
top_start : RoundedRadius,
|
||||
top_end : RoundedRadius,
|
||||
bottom_start: RoundedRadius,
|
||||
bottom_end : RoundedRadius,
|
||||
}
|
||||
|
||||
impl Rounded {
|
||||
/// Prepara las esquinas **sin redondeo global** de partida.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Crea las esquinas **con redondeo global** (`radius`).
|
||||
pub fn with(radius: RoundedRadius) -> Self {
|
||||
Self::default().with_radius(radius)
|
||||
}
|
||||
|
||||
// **< Rounded BUILDER >************************************************************************
|
||||
|
||||
/// Establece el radio global de las esquinas (`rounded*`).
|
||||
pub fn with_radius(mut self, radius: RoundedRadius) -> Self {
|
||||
self.radius = radius;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el radio en las esquinas del lado superior (`rounded-top-*`).
|
||||
pub fn with_top(mut self, radius: RoundedRadius) -> Self {
|
||||
self.top = radius;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el radio en las esquinas del lado lógico final (`rounded-end-*`). Respeta LTR/RTL.
|
||||
pub fn with_end(mut self, radius: RoundedRadius) -> Self {
|
||||
self.end = radius;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el radio en las esquinas del lado inferior (`rounded-bottom-*`).
|
||||
pub fn with_bottom(mut self, radius: RoundedRadius) -> Self {
|
||||
self.bottom = radius;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el radio en las esquinas del lado lógico inicial (`rounded-start-*`). Respeta
|
||||
/// LTR/RTL.
|
||||
pub fn with_start(mut self, radius: RoundedRadius) -> Self {
|
||||
self.start = radius;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el radio en la esquina superior-inicial (`rounded-top-start-*`). Respeta LTR/RTL.
|
||||
pub fn with_top_start(mut self, radius: RoundedRadius) -> Self {
|
||||
self.top_start = radius;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el radio en la esquina superior-final (`rounded-top-end-*`). Respeta LTR/RTL.
|
||||
pub fn with_top_end(mut self, radius: RoundedRadius) -> Self {
|
||||
self.top_end = radius;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el radio en la esquina inferior-inicial (`rounded-bottom-start-*`). Respeta
|
||||
/// LTR/RTL.
|
||||
pub fn with_bottom_start(mut self, radius: RoundedRadius) -> Self {
|
||||
self.bottom_start = radius;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el radio en la esquina inferior-final (`rounded-bottom-end-*`). Respeta LTR/RTL.
|
||||
pub fn with_bottom_end(mut self, radius: RoundedRadius) -> Self {
|
||||
self.bottom_end = radius;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Rounded {
|
||||
/// Concatena cada definición en el orden: *global*, `top`, `end`, `bottom`, `start`,
|
||||
/// `top-start`, `top-end`, `bottom-start` y `bottom-end`; respetando LTR/RTL y omitiendo las
|
||||
/// definiciones vacías.
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
join_opt!([
|
||||
self.radius.to_string(),
|
||||
self.top.to_class("rounded-top"),
|
||||
self.end.to_class("rounded-end"),
|
||||
self.bottom.to_class("rounded-bottom"),
|
||||
self.start.to_class("rounded-start"),
|
||||
self.top_start.to_class("rounded-top-start"),
|
||||
self.top_end.to_class("rounded-top-end"),
|
||||
self.bottom_start.to_class("rounded-bottom-start"),
|
||||
self.bottom_end.to_class("rounded-bottom-end"),
|
||||
]; " ")
|
||||
.unwrap_or_default()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
// **< ButtonSize >*********************************************************************************
|
||||
|
||||
/// Tamaño visual de un botón.
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ButtonSize {
|
||||
/// Tamaño por defecto del tema (no añade clase).
|
||||
#[default]
|
||||
Default,
|
||||
/// Botón compacto.
|
||||
Small,
|
||||
/// Botón destacado/grande.
|
||||
Large,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl fmt::Display for ButtonSize {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Default => Ok(()),
|
||||
Self::Small => f.write_str("btn-sm"),
|
||||
Self::Large => f.write_str("btn-lg"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue