♻️ (bootsier): Sustituye BreakPoint por Breakpoint
Elimina el enum BreakPoint propio de Bootsier. Los componentes pasan a usar el Breakpoint del núcleo, cuyo nombre y ancho resuelve el tema activo.
This commit is contained in:
parent
307ca6f62c
commit
5bf28ef4f0
10 changed files with 185 additions and 113 deletions
|
|
@ -125,21 +125,38 @@ impl Extension for Bootsier {
|
|||
|
||||
#[async_trait]
|
||||
impl Theme for Bootsier {
|
||||
#[rustfmt::skip]
|
||||
fn breakpoint_entry(&self, bp: Breakpoint) -> BreakpointEntry {
|
||||
use Breakpoint::*;
|
||||
|
||||
// Anchos mínimos de la rejilla de Bootstrap (`$grid-breakpoints`). Bootstrap no tiene un
|
||||
// punto de corte por encima de `xxl`, así que `Xxxl` se resuelve como `xxl`.
|
||||
match bp {
|
||||
Xs => BreakpointEntry { breakpoint: Xs, name: "xs", min_width: "" },
|
||||
Sm => BreakpointEntry { breakpoint: Sm, name: "sm", min_width: "576px" },
|
||||
Md => BreakpointEntry { breakpoint: Md, name: "md", min_width: "768px" },
|
||||
Lg => BreakpointEntry { breakpoint: Lg, name: "lg", min_width: "992px" },
|
||||
Xl => BreakpointEntry { breakpoint: Xl, name: "xl", min_width: "1200px" },
|
||||
Xxl => BreakpointEntry { breakpoint: Xxl, name: "xxl", min_width: "1400px" },
|
||||
Xxxl => BreakpointEntry { breakpoint: Xxxl, name: "xxl", min_width: "1400px" },
|
||||
}
|
||||
}
|
||||
|
||||
fn intent_color(&self, intent: Intent) -> &'static str {
|
||||
theme::BootsierColors::from(intent).as_str()
|
||||
}
|
||||
|
||||
fn setup_component(&self, component: &mut dyn Component, _cx: &mut Context) {
|
||||
fn setup_component(&self, component: &mut dyn Component, cx: &mut Context) {
|
||||
setup_component!(component, {
|
||||
Badge => |c| theme::bs::badge::setup(c),
|
||||
Brand => |c| theme::bs::brand::setup(c),
|
||||
Button => |c| theme::bs::button::setup(c),
|
||||
Container => |c| theme::bs::container::setup(c),
|
||||
Container => |c| theme::bs::container::setup(c, cx),
|
||||
Dialog => |c| theme::bs::dialog::setup(c),
|
||||
Dropdown => |c| theme::bs::dropdown::setup(c),
|
||||
Image => |c| theme::bs::image::setup(c),
|
||||
Nav => |c| theme::bs::nav::setup(c),
|
||||
Navbar => |c| theme::bs::navbar::setup(c),
|
||||
Navbar => |c| theme::bs::navbar::setup(c, cx),
|
||||
form::input::Field => |c| theme::bs::form::input::setup(c),
|
||||
form::select::Field => |c| theme::bs::form::select::setup(c),
|
||||
form::Textarea => |c| theme::bs::form::textarea::setup(c),
|
||||
|
|
|
|||
|
|
@ -11,13 +11,10 @@
|
|||
//!
|
||||
//! # Plantillas
|
||||
//!
|
||||
//! Bootsier maqueta las dos plantillas de PageTop
|
||||
//! ([`CoreTemplates`](pagetop::prelude::CoreTemplates)): `Standard`, con
|
||||
//! cabecera, contenido y pie, que es la plantilla por defecto de cualquier página; y `Admin`, con
|
||||
//! la shell completa de AdminLTE 4 (barra superior + barra lateral + área de contenido), que se
|
||||
//! activa creando la página con [`Page::admin()`](pagetop::response::Page::admin) en lugar de
|
||||
//! [`Page::new()`](pagetop::response::Page::new). No define sus propias variantes de plantilla:
|
||||
//! intercepta el componente `Template` en `render_component()` (ver `bs::layout`).
|
||||
//! Bootsier maqueta las dos plantillas de PageTop ([`CoreTemplates`]): `Standard`, con cabecera,
|
||||
//! contenido y pie, que es la plantilla por defecto de cualquier página; y `Admin`, con la shell
|
||||
//! completa de administración (barra superior + barra lateral + área de contenido), que se activa
|
||||
//! creando la página con [`Page::admin()`] en lugar de [`Page::new()`].
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use pagetop::prelude::*;
|
||||
|
|
@ -32,6 +29,10 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`CoreTemplates`]: pagetop::prelude::CoreTemplates
|
||||
//! [`Page::admin()`]: pagetop::response::Page::admin
|
||||
//! [`Page::new()`]: pagetop::response::Page::new
|
||||
//!
|
||||
//! # Barra lateral
|
||||
//!
|
||||
//! Registra elementos en [`BootsierRegions::Sidebar`](bs::BootsierRegions::Sidebar) para poblar la
|
||||
|
|
@ -88,6 +89,8 @@
|
|||
//! }));
|
||||
//! ```
|
||||
|
||||
use pagetop::prelude::*;
|
||||
|
||||
pub mod bs;
|
||||
|
||||
pub mod class;
|
||||
|
|
@ -113,3 +116,35 @@ pub use bs::form::textarea::TextareaBootsier;
|
|||
pub use bs::nav::NavBootsier;
|
||||
#[doc(hidden)]
|
||||
pub use bs::navbar::NavbarBootsier;
|
||||
|
||||
// Añade la clase de un punto de corte con un prefijo y un sufijo (opcional) a la cadena de clases,
|
||||
// separada con un espacio de las que ya hubiera: `prefix-name-suffix`, sin `-suffix` si no hay
|
||||
// sufijo, y sin `-name` si el punto de corte aplica siempre.
|
||||
//
|
||||
// `name` es el nombre del punto de corte según `Theme::breakpoint_entry()` en el tema activo de
|
||||
// `cx`. Si el tema no le asocia un ancho mínimo (`Breakpoint::resolved()` devuelve `None`), el
|
||||
// punto de corte aplica siempre y se omite `name`, igual que Bootstrap con `container` frente a
|
||||
// `container-lg`, o `container-fluid` frente a `container-lg-fluid`.
|
||||
pub(crate) fn push_breakpoint_class(
|
||||
cx: &Context,
|
||||
bp: Breakpoint,
|
||||
classes: &mut String,
|
||||
prefix: &str,
|
||||
suffix: &str,
|
||||
) {
|
||||
if prefix.is_empty() {
|
||||
return;
|
||||
}
|
||||
if !classes.is_empty() {
|
||||
classes.push(' ');
|
||||
}
|
||||
classes.push_str(prefix);
|
||||
if let Some(entry) = bp.resolved(cx) {
|
||||
classes.push('-');
|
||||
classes.push_str(entry.name);
|
||||
}
|
||||
if !suffix.is_empty() {
|
||||
classes.push('-');
|
||||
classes.push_str(suffix);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const EXTRA_WIDTH: &str = "bootsier.container.width";
|
|||
///
|
||||
/// let main = bs::Container::main()
|
||||
/// .with_id("main-page")
|
||||
/// .with_width(bs::container::Width::From(BreakPoint::LG))
|
||||
/// .with_width(bs::container::Width::From(Breakpoint::Lg))
|
||||
/// .with_prop(PropsOp::add_classes(class::Bg::with(BootsierColors::Light)))
|
||||
/// .with_prop(PropsOp::add_classes(class::Text::with(BootsierColors::Dark)))
|
||||
/// .with_prop(PropsOp::add_classes(class::Border::with(ScaleSize::One)))
|
||||
|
|
@ -61,7 +61,7 @@ pub enum Width {
|
|||
Default,
|
||||
/// Aplica los anchos máximos predefinidos a partir del punto de ruptura indicado. Por debajo de
|
||||
/// ese punto de ruptura ocupa el 100% del ancho disponible.
|
||||
From(BreakPoint),
|
||||
From(Breakpoint),
|
||||
/// Ocupa el 100% del ancho disponible siempre.
|
||||
Fluid,
|
||||
/// Ocupa el 100% del ancho disponible hasta un ancho máximo explícito.
|
||||
|
|
@ -72,30 +72,34 @@ impl Width {
|
|||
const CONTAINER: &str = "container";
|
||||
|
||||
/// Añade la clase asociada al ancho del contenedor a la cadena de clases.
|
||||
///
|
||||
/// El nombre del punto de ruptura se resuelve en el tema activo de `cx`.
|
||||
#[inline]
|
||||
pub fn push_to(self, classes: &mut String) {
|
||||
pub fn push_to(self, cx: &Context, classes: &mut String) {
|
||||
match self {
|
||||
Self::Default => BreakPoint::None.push_to(classes, Self::CONTAINER, ""),
|
||||
Self::From(bp) => bp.push_to(classes, Self::CONTAINER, ""),
|
||||
Self::Default => {
|
||||
push_breakpoint_class(cx, Breakpoint::Xs, classes, Self::CONTAINER, "")
|
||||
}
|
||||
Self::From(bp) => push_breakpoint_class(cx, bp, classes, Self::CONTAINER, ""),
|
||||
Self::Fluid | Self::FluidMax(_) => {
|
||||
BreakPoint::None.push_to(classes, Self::CONTAINER, "fluid")
|
||||
push_breakpoint_class(cx, Breakpoint::Xs, classes, Self::CONTAINER, "fluid")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Devuelve la clase asociada al ancho del contenedor.
|
||||
pub fn to_class(self) -> String {
|
||||
pub fn to_class(self, cx: &Context) -> String {
|
||||
let mut class = String::new();
|
||||
self.push_to(&mut class);
|
||||
self.push_to(cx, &mut class);
|
||||
class
|
||||
}
|
||||
}
|
||||
|
||||
// **< Container SETUP >****************************************************************************
|
||||
|
||||
pub(crate) fn setup(container: &mut Container) {
|
||||
pub(crate) fn setup(container: &mut Container, cx: &Context) {
|
||||
let width = container.props().extra_or(EXTRA_WIDTH, Width::default());
|
||||
container.alter_prop(PropsOp::prepend_classes(width.to_class()));
|
||||
container.alter_prop(PropsOp::prepend_classes(width.to_class(cx)));
|
||||
if let Width::FluidMax(w) = width
|
||||
&& w.is_measurable()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ pub(crate) async fn render(
|
|||
let auto_close = auto_close.opt_str();
|
||||
let menu_classes = {
|
||||
let mut classes = "dropdown-menu".to_string();
|
||||
menu_align.push_to(&mut classes);
|
||||
menu_align.push_to(cx, &mut classes);
|
||||
classes
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -112,65 +112,69 @@ impl Direction {
|
|||
/// Alineación horizontal del menú desplegable [`Dropdown`](crate::theme::bs::Dropdown).
|
||||
///
|
||||
/// Permite alinear el menú al inicio o al final del botón (respetando LTR/RTL) y añadirle una
|
||||
/// alineación diferente a partir de un punto de ruptura ([`BreakPoint`]).
|
||||
/// alineación diferente a partir de un punto de ruptura ([`Breakpoint`]).
|
||||
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
||||
pub enum MenuAlign {
|
||||
/// Alineación al inicio (comportamiento por defecto).
|
||||
#[default]
|
||||
Start,
|
||||
/// Alineación al inicio a partir del punto de ruptura indicado.
|
||||
StartAt(BreakPoint),
|
||||
StartAt(Breakpoint),
|
||||
/// Alineación al inicio por defecto, y al final a partir de un punto de ruptura válido.
|
||||
StartAndEnd(BreakPoint),
|
||||
StartAndEnd(Breakpoint),
|
||||
/// Alineación al final.
|
||||
End,
|
||||
/// Alineación al final a partir del punto de ruptura indicado.
|
||||
EndAt(BreakPoint),
|
||||
EndAt(Breakpoint),
|
||||
/// Alineación al final por defecto, y al inicio a partir de un punto de ruptura válido.
|
||||
EndAndStart(BreakPoint),
|
||||
EndAndStart(Breakpoint),
|
||||
}
|
||||
|
||||
impl MenuAlign {
|
||||
/// Añade las clases de alineación a la cadena de clases (sin incluir la base `dropdown-menu`).
|
||||
///
|
||||
/// El nombre del punto de ruptura se resuelve en el tema activo de `cx`.
|
||||
#[inline]
|
||||
pub fn push_to(self, classes: &mut String) {
|
||||
pub fn push_to(self, cx: &Context, classes: &mut String) {
|
||||
const MENU: &str = "dropdown-menu";
|
||||
|
||||
match self {
|
||||
// Alineación por defecto (start), no añade clases extra.
|
||||
Self::Start => {}
|
||||
|
||||
// `dropdown-menu-{bp}-start`
|
||||
Self::StartAt(bp) => {
|
||||
bp.push_to(classes, "dropdown-menu", "start");
|
||||
push_breakpoint_class(cx, bp, classes, MENU, "start");
|
||||
}
|
||||
|
||||
// `dropdown-menu-start` + `dropdown-menu-{bp}-end`
|
||||
Self::StartAndEnd(bp) => {
|
||||
BreakPoint::None.push_to(classes, "dropdown-menu", "start");
|
||||
bp.push_to(classes, "dropdown-menu", "end");
|
||||
push_breakpoint_class(cx, Breakpoint::Xs, classes, MENU, "start");
|
||||
push_breakpoint_class(cx, bp, classes, MENU, "end");
|
||||
}
|
||||
|
||||
// `dropdown-menu-end`
|
||||
Self::End => {
|
||||
BreakPoint::None.push_to(classes, "dropdown-menu", "end");
|
||||
push_breakpoint_class(cx, Breakpoint::Xs, classes, MENU, "end");
|
||||
}
|
||||
|
||||
// `dropdown-menu-{bp}-end`
|
||||
Self::EndAt(bp) => {
|
||||
bp.push_to(classes, "dropdown-menu", "end");
|
||||
push_breakpoint_class(cx, bp, classes, MENU, "end");
|
||||
}
|
||||
|
||||
// `dropdown-menu-end` + `dropdown-menu-{bp}-start`
|
||||
Self::EndAndStart(bp) => {
|
||||
BreakPoint::None.push_to(classes, "dropdown-menu", "end");
|
||||
bp.push_to(classes, "dropdown-menu", "start");
|
||||
push_breakpoint_class(cx, Breakpoint::Xs, classes, MENU, "end");
|
||||
push_breakpoint_class(cx, bp, classes, MENU, "start");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Devuelve las clases de alineación del menú (sin incluir la base `dropdown-menu`).
|
||||
pub fn to_class(self) -> String {
|
||||
pub fn to_class(self, cx: &Context) -> String {
|
||||
let mut classes = String::new();
|
||||
self.push_to(&mut classes);
|
||||
self.push_to(cx, &mut classes);
|
||||
classes
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ const EXTRA_EXPAND: &str = "bootsier.navbar.expand";
|
|||
/// # use pagetop::prelude::*;
|
||||
/// # use pagetop_bootsier::theme::*;
|
||||
/// let navbar = bs::Navbar::simple_toggle()
|
||||
/// .with_expand(BreakPoint::MD)
|
||||
/// .with_expand(Breakpoint::Md)
|
||||
/// .with_item(bs::navbar::Item::nav(
|
||||
/// bs::Nav::new()
|
||||
/// .with_item(bs::nav::Item::link(Lc::n("Home"), "/"))
|
||||
|
|
@ -88,7 +88,7 @@ const EXTRA_EXPAND: &str = "bootsier.navbar.expand";
|
|||
/// .with_route(Route::from("/"));
|
||||
///
|
||||
/// let navbar = bs::Navbar::brand_right(brand)
|
||||
/// .with_expand(BreakPoint::LG)
|
||||
/// .with_expand(Breakpoint::Lg)
|
||||
/// .with_item(bs::navbar::Item::nav(
|
||||
/// bs::Nav::new()
|
||||
/// .with_kind(bs::nav::Kind::Pills)
|
||||
|
|
@ -152,7 +152,7 @@ pub trait NavbarBootsier {
|
|||
fn offcanvas_brand_right(brand: Brand, oc: bs::Offcanvas) -> Self;
|
||||
|
||||
/// Define a partir de qué punto de ruptura la barra de navegación deja de colapsar.
|
||||
fn with_expand(self, bp: BreakPoint) -> Self;
|
||||
fn with_expand(self, bp: Breakpoint) -> Self;
|
||||
|
||||
/// Define dónde se mostrará la barra de navegación dentro del documento.
|
||||
fn with_position(self, position: bs::navbar::Position) -> Self;
|
||||
|
|
@ -187,7 +187,7 @@ impl NavbarBootsier for Navbar {
|
|||
navbar
|
||||
}
|
||||
|
||||
fn with_expand(mut self, bp: BreakPoint) -> Self {
|
||||
fn with_expand(mut self, bp: Breakpoint) -> Self {
|
||||
self.alter_prop(PropsOp::set_extra(EXTRA_EXPAND, bp));
|
||||
self
|
||||
}
|
||||
|
|
@ -200,15 +200,15 @@ impl NavbarBootsier for Navbar {
|
|||
|
||||
// **< Navbar SETUP >*******************************************************************************
|
||||
|
||||
pub(crate) fn setup(navbar: &mut Navbar) {
|
||||
pub(crate) fn setup(navbar: &mut Navbar, cx: &Context) {
|
||||
// Sin `with_expand()`, colapsa por debajo de 768px, igual que el tema Basic (que no tiene
|
||||
// punto de ruptura configurable y siempre usa ese umbral, ver `static/css/basic.css`).
|
||||
let expand = navbar.props().extra_or(EXTRA_EXPAND, BreakPoint::MD);
|
||||
let expand = navbar.props().extra_or(EXTRA_EXPAND, Breakpoint::Md);
|
||||
let position = navbar
|
||||
.props()
|
||||
.extra_or(EXTRA_POSITION, bs::navbar::Position::default());
|
||||
let mut classes = String::new();
|
||||
expand.push_to(&mut classes, "navbar-expand", "");
|
||||
push_breakpoint_class(cx, expand, &mut classes, "navbar-expand", "");
|
||||
position.push_to(&mut classes);
|
||||
if !classes.is_empty() {
|
||||
navbar.alter_prop(PropsOp::add_classes(classes));
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ pub struct Offcanvas {
|
|||
/// Devuelve el título del panel.
|
||||
title: Lc,
|
||||
/// Devuelve el punto de ruptura configurado para cambiar el comportamiento del panel.
|
||||
breakpoint: BreakPoint,
|
||||
breakpoint: Breakpoint,
|
||||
/// Devuelve el comportamiento configurado para la capa de fondo.
|
||||
backdrop: bs::offcanvas::Backdrop,
|
||||
/// Indica si la página principal puede desplazarse mientras el panel está abierto.
|
||||
|
|
@ -77,8 +77,8 @@ impl Component for Offcanvas {
|
|||
|
||||
// Clases CSS por defecto para el panel.
|
||||
self.alter_prop(PropsOp::prepend_classes({
|
||||
let mut classes = "offcanvas".to_string();
|
||||
self.breakpoint().push_to(&mut classes, "offcanvas", "");
|
||||
let mut classes = String::new();
|
||||
push_breakpoint_class(cx, *self.breakpoint(), &mut classes, "offcanvas", "");
|
||||
self.placement().push_to(&mut classes);
|
||||
self.visibility().push_to(&mut classes);
|
||||
classes
|
||||
|
|
@ -118,10 +118,10 @@ impl Offcanvas {
|
|||
/// ([`Offcanvas`]).
|
||||
/// - **Por encima**, el contenido del panel se muestra tal cual, integrado en la página.
|
||||
///
|
||||
/// Por ejemplo, con `BreakPoint::Lg`, será *offcanvas* en móviles y tabletas, y visible
|
||||
/// directamente en pantallas grandes. Por defecto usa `BreakPoint::None` para que sea
|
||||
/// Por ejemplo, con `Breakpoint::Lg`, será *offcanvas* en móviles y tabletas, y visible
|
||||
/// directamente en pantallas grandes. Por defecto usa `Breakpoint::Xs` para que sea
|
||||
/// *offcanvas* siempre.
|
||||
pub fn with_breakpoint(mut self, bp: BreakPoint) -> Self {
|
||||
pub fn with_breakpoint(mut self, bp: Breakpoint) -> Self {
|
||||
self.breakpoint = bp;
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
//! Tipos enumerados para construir clases del tema.
|
||||
|
||||
mod breakpoint;
|
||||
pub use breakpoint::BreakPoint;
|
||||
|
||||
mod color;
|
||||
pub use color::{BootsierColors, OpacityLevel};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
/// Puntos de ruptura (*breakpoints*) para aplicar diseño *responsive*.
|
||||
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
||||
pub enum BreakPoint {
|
||||
/// **Menos de 576px**. Dispositivos muy pequeños: teléfonos en modo vertical.
|
||||
#[default]
|
||||
None,
|
||||
/// **576px o más**. Dispositivos pequeños: teléfonos en modo horizontal.
|
||||
SM,
|
||||
/// **768px o más**. Dispositivos medianos: tabletas.
|
||||
MD,
|
||||
/// **992px o más**. Dispositivos grandes: puestos de escritorio.
|
||||
LG,
|
||||
/// **1200px o más**. Dispositivos muy grandes: puestos de escritorio grandes.
|
||||
XL,
|
||||
/// **1400px o más**. Dispositivos extragrandes: puestos de escritorio más grandes.
|
||||
XXL,
|
||||
}
|
||||
|
||||
impl BreakPoint {
|
||||
/// Devuelve la identificación del punto de ruptura (`"sm"`, `"md"`, etc.), o `""` para `None`.
|
||||
#[rustfmt::skip]
|
||||
#[inline]
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::None => "",
|
||||
Self::SM => "sm",
|
||||
Self::MD => "md",
|
||||
Self::LG => "lg",
|
||||
Self::XL => "xl",
|
||||
Self::XXL => "xxl",
|
||||
}
|
||||
}
|
||||
|
||||
// Añade el punto de ruptura con un prefijo y un sufijo (opcional) a la cadena de clases.
|
||||
//
|
||||
// - Para `None`: `prefix` o `prefix-suffix` (si `suffix` no está vacío).
|
||||
// - Para `SM..XXL`: `prefix-{breakpoint}` o `prefix-{breakpoint}-{suffix}`.
|
||||
#[inline]
|
||||
pub(crate) fn push_to(self, classes: &mut String, prefix: &str, suffix: &str) {
|
||||
if prefix.is_empty() {
|
||||
return;
|
||||
}
|
||||
if !classes.is_empty() {
|
||||
classes.push(' ');
|
||||
}
|
||||
match self {
|
||||
Self::None => classes.push_str(prefix),
|
||||
_ => {
|
||||
classes.push_str(prefix);
|
||||
classes.push('-');
|
||||
classes.push_str(self.as_str());
|
||||
}
|
||||
}
|
||||
if !suffix.is_empty() {
|
||||
classes.push('-');
|
||||
classes.push_str(suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
76
extensions/pagetop-bootsier/tests/breakpoint_class.rs
Normal file
76
extensions/pagetop-bootsier/tests/breakpoint_class.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Verifies that Bootsier builds its breakpoint-based Bootstrap classes from the breakpoint names
|
||||
// of `Bootsier::breakpoint_entry()`, and that `Xxxl` (absent in Bootstrap) resolves as `xxl`.
|
||||
|
||||
use pagetop::prelude::*;
|
||||
use pagetop_bootsier::theme::*;
|
||||
|
||||
fn cx() -> Context {
|
||||
Context::default().with_theme(&pagetop_bootsier::Bootsier)
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn container_width_uses_breakpoint_name() {
|
||||
let cx = cx();
|
||||
assert_eq!(bs::container::Width::Default.to_class(&cx), "container");
|
||||
assert_eq!(bs::container::Width::Fluid.to_class(&cx), "container-fluid");
|
||||
assert_eq!(
|
||||
bs::container::Width::From(Breakpoint::Lg).to_class(&cx),
|
||||
"container-lg"
|
||||
);
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn container_width_xxxl_resolves_as_xxl() {
|
||||
let cx = cx();
|
||||
assert_eq!(
|
||||
bs::container::Width::From(Breakpoint::Xxxl).to_class(&cx),
|
||||
"container-xxl"
|
||||
);
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn dropdown_menu_align_combines_breakpoint_classes() {
|
||||
let cx = cx();
|
||||
assert_eq!(bs::dropdown::MenuAlign::Start.to_class(&cx), "");
|
||||
assert_eq!(
|
||||
bs::dropdown::MenuAlign::EndAt(Breakpoint::Md).to_class(&cx),
|
||||
"dropdown-menu-md-end"
|
||||
);
|
||||
assert_eq!(
|
||||
bs::dropdown::MenuAlign::StartAndEnd(Breakpoint::Xl).to_class(&cx),
|
||||
"dropdown-menu-start dropdown-menu-xl-end"
|
||||
);
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn navbar_expands_at_md_by_default_and_at_the_chosen_breakpoint() {
|
||||
let item =
|
||||
|| bs::navbar::Item::nav(bs::Nav::new().with_item(bs::nav::Item::link(Lc::n("Home"), "/")));
|
||||
|
||||
let mut navbar = bs::Navbar::simple().with_item(item());
|
||||
let html = navbar.render(&mut cx()).await.into_string();
|
||||
assert!(html.contains("navbar-expand-md"));
|
||||
|
||||
let mut navbar = bs::Navbar::simple()
|
||||
.with_expand(Breakpoint::Xxxl)
|
||||
.with_item(item());
|
||||
let html = navbar.render(&mut cx()).await.into_string();
|
||||
assert!(html.contains("navbar-expand-xxl"));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn offcanvas_uses_either_the_plain_or_the_breakpoint_class() {
|
||||
// Bootstrap's `.offcanvas` is always fixed, so it must not accompany `.offcanvas-{bp}`.
|
||||
let panel =
|
||||
|offcanvas: bs::Offcanvas| offcanvas.with_child(Html::with(|_| html! { p { "Content" } }));
|
||||
|
||||
let mut plain = panel(bs::Offcanvas::new());
|
||||
let html = plain.render(&mut cx()).await.into_string();
|
||||
assert!(html.contains(r#"class="offcanvas "#));
|
||||
assert!(!html.contains("offcanvas-lg"));
|
||||
|
||||
let mut responsive = panel(bs::Offcanvas::new().with_breakpoint(Breakpoint::Lg));
|
||||
let html = responsive.render(&mut cx()).await.into_string();
|
||||
assert!(html.contains(r#"class="offcanvas-lg "#));
|
||||
assert!(!html.contains(r#"class="offcanvas "#));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue