✨ (bootsier): Añade componentes esenciales

- Añade Dialog como modal de Bootstrap, con el JS de soporte para
  `htmx:confirm` y el saneado de su posición fija.
- Adapta Nav, Navbar y Dropdown al reuso de los tipos movidos al core, y
  traduce BootsierColors/Intent en Button y Badge, con soporte para
  Light/Dark vía with_color().
- Reexporta en el tema los componentes de PageTop que faltaban: Block,
  Breadcrumb, Messages, Pager, Table y form::Number.
This commit is contained in:
Manuel Cillero 2026-08-28 19:46:56 +02:00
parent eb63a7ef37
commit c0a5a8c3ab
47 changed files with 2135 additions and 1818 deletions

View file

@ -1,14 +1,57 @@
use pagetop::prelude::*;
use crate::theme::BootsierColors;
pub use pagetop::base::component::Badge;
const EXTRA_COLOR: &str = "bootsier.badge.color";
/// Extensión de Bootsier para [`Badge`].
///
/// Permite forzar un color de la paleta de Bootsier ([`BootsierColors`]) en vez del que le
/// correspondería por defecto a la [`Intent`] del badge -- por ejemplo, para usar `Light`/`Dark`,
/// que `Intent` no tiene.
///
/// ```rust,no_run
/// use pagetop::prelude::*;
/// use pagetop_bootsier::theme::*;
///
/// let badge = bs::Badge::labeled(Lc::n("Beta")).with_color(BootsierColors::Dark);
/// ```
pub trait BadgeBootsier {
/// Fuerza un color de la paleta de Bootsier, ignorando el que le correspondería a la `Intent`
/// del badge. `None` restablece el comportamiento por defecto (color derivado de la `Intent`).
#[builder_fn]
fn with_color(self, color: impl Into<Option<BootsierColors>>) -> Self;
}
impl BadgeBootsier for Badge {
#[builder_fn]
fn with_color(mut self, color: impl Into<Option<BootsierColors>>) -> Self {
match color.into() {
Some(color) => self.alter_prop(PropsOp::set_extra(EXTRA_COLOR, color)),
None => self.alter_prop(PropsOp::remove_extra(EXTRA_COLOR)),
};
self
}
}
// **< Badge SETUP >********************************************************************************
pub(crate) fn setup(badge: &mut Badge) {
let intent = badge.intent().as_str();
// `Badge::setup()` (core) ya ha traducido la intención con `Theme::intent_color()` -- la clase
// `badge-*` que hay que localizar es siempre la derivada de la `Intent`, con independencia de
// que `BadgeBootsier::with_color()` fuerce un color distinto para el destino `text-bg-*`.
let intent_color = BootsierColors::from(badge.intent()).as_str();
let color = badge
.props()
.extra::<BootsierColors>(EXTRA_COLOR)
.ok()
.copied()
.map_or(intent_color, |color| color.as_str());
badge.alter_prop(PropsOp::replace_classes(
util::join!("badge-", intent),
util::join!("text-bg-", intent),
util::join!("badge-", intent_color),
util::join!("text-bg-", color),
));
}