✨ (pagetop): Añade with_expand() a Navbar
Navbar guarda el punto de corte a partir del cual deja de colapsar
(`Breakpoint::Md` por defecto) y añade la clase `navbar-expand-{nombre}`
o `navbar-expand` si no tiene ancho mínimo. El nombre lo resuelve el
tema activo con `Theme::breakpoint_entry()`.
This commit is contained in:
parent
5bf28ef4f0
commit
9143f1eb26
10 changed files with 271 additions and 49 deletions
|
|
@ -353,11 +353,13 @@ body {
|
|||
display: block;
|
||||
}
|
||||
|
||||
/* Options and headers stay on one line, so the menu grows to fit the longest one. */
|
||||
.dropdown-item {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0.375rem 1rem;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
color: var(--val-color--text);
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
|
|
@ -387,6 +389,7 @@ body {
|
|||
display: block;
|
||||
padding: 0.5rem 1rem 0.25rem;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
color: var(--val-color--text--muted);
|
||||
|
|
@ -672,28 +675,182 @@ input:disabled + label {
|
|||
color: var(--val-color--text--muted);
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.navbar {
|
||||
/*
|
||||
* A navbar with a toggle button collapses below the breakpoint set by its `navbar-expand-{name}`
|
||||
* class, added by the `Navbar` component. `navbar-expand` alone (a breakpoint with no minimum
|
||||
* width) never collapses and needs no rules, since the base rules above are the expanded layout.
|
||||
* The widths below match the default `Theme::breakpoint_entry()` table, so a child theme that
|
||||
* renames or resizes the breakpoints must also redefine these classes.
|
||||
*
|
||||
* While collapsed, the `.nav` items are stacked in a column, so a dropdown menu inside it is laid
|
||||
* out in the flow (`position: static`) to push down the following items instead of covering them.
|
||||
*/
|
||||
@media (max-width: 575.98px) {
|
||||
.navbar-expand-sm {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.navbar:has(.navbar-toggle) .navbar-toggle {
|
||||
.navbar-expand-sm:has(.navbar-toggle) .navbar-toggle {
|
||||
display: inline-block;
|
||||
order: -1;
|
||||
}
|
||||
.navbar:has(.navbar-toggle) .navbar-content {
|
||||
.navbar-expand-sm:has(.navbar-toggle) .navbar-content {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar:has(.navbar-toggle) .navbar-content.show {
|
||||
.navbar-expand-sm:has(.navbar-toggle) .navbar-content.show {
|
||||
display: flex;
|
||||
}
|
||||
.navbar .nav {
|
||||
.navbar-expand-sm .nav {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-sm .nav .dropdown-menu {
|
||||
position: static;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.navbar-expand-md {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.navbar-expand-md:has(.navbar-toggle) .navbar-toggle {
|
||||
display: inline-block;
|
||||
order: -1;
|
||||
}
|
||||
.navbar-expand-md:has(.navbar-toggle) .navbar-content {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-md:has(.navbar-toggle) .navbar-content.show {
|
||||
display: flex;
|
||||
}
|
||||
.navbar-expand-md .nav {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-md .nav .dropdown-menu {
|
||||
position: static;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.navbar-expand-lg {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.navbar-expand-lg:has(.navbar-toggle) .navbar-toggle {
|
||||
display: inline-block;
|
||||
order: -1;
|
||||
}
|
||||
.navbar-expand-lg:has(.navbar-toggle) .navbar-content {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-lg:has(.navbar-toggle) .navbar-content.show {
|
||||
display: flex;
|
||||
}
|
||||
.navbar-expand-lg .nav {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-lg .nav .dropdown-menu {
|
||||
position: static;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1199.98px) {
|
||||
.navbar-expand-xl {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.navbar-expand-xl:has(.navbar-toggle) .navbar-toggle {
|
||||
display: inline-block;
|
||||
order: -1;
|
||||
}
|
||||
.navbar-expand-xl:has(.navbar-toggle) .navbar-content {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-xl:has(.navbar-toggle) .navbar-content.show {
|
||||
display: flex;
|
||||
}
|
||||
.navbar-expand-xl .nav {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-xl .nav .dropdown-menu {
|
||||
position: static;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1399.98px) {
|
||||
.navbar-expand-xxl {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.navbar-expand-xxl:has(.navbar-toggle) .navbar-toggle {
|
||||
display: inline-block;
|
||||
order: -1;
|
||||
}
|
||||
.navbar-expand-xxl:has(.navbar-toggle) .navbar-content {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-xxl:has(.navbar-toggle) .navbar-content.show {
|
||||
display: flex;
|
||||
}
|
||||
.navbar-expand-xxl .nav {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-xxl .nav .dropdown-menu {
|
||||
position: static;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1919.98px) {
|
||||
.navbar-expand-xxxl {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.navbar-expand-xxxl:has(.navbar-toggle) .navbar-toggle {
|
||||
display: inline-block;
|
||||
order: -1;
|
||||
}
|
||||
.navbar-expand-xxxl:has(.navbar-toggle) .navbar-content {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-xxxl:has(.navbar-toggle) .navbar-content.show {
|
||||
display: flex;
|
||||
}
|
||||
.navbar-expand-xxxl .nav {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-expand-xxxl .nav .dropdown-menu {
|
||||
position: static;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ impl Theme for Bootsier {
|
|||
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, cx),
|
||||
Navbar => |c| theme::bs::navbar::setup(c),
|
||||
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),
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ const EXTRA_WIDTH: &str = "bootsier.container.width";
|
|||
pub trait ContainerBootsier {
|
||||
/// Establece el comportamiento del ancho para el contenedor.
|
||||
///
|
||||
/// Determina si el contenedor aplica los anchos máximos predefinidos para cada punto de
|
||||
/// ruptura, o si ocupa siempre el 100% del ancho disponible, o lo hace hasta un ancho máximo
|
||||
/// explícito. Ver [`Width`] para las variantes disponibles.
|
||||
/// Determina si el contenedor aplica los anchos máximos predefinidos para cada punto de corte,
|
||||
/// o si ocupa siempre el 100% del ancho disponible, o lo hace hasta un ancho máximo explícito.
|
||||
/// Ver [`Width`] para las variantes disponibles.
|
||||
fn with_width(self, width: Width) -> Self;
|
||||
}
|
||||
|
||||
|
|
@ -55,12 +55,12 @@ impl ContainerBootsier for Container {
|
|||
/// Define cómo se comporta el ancho de un contenedor ([`Container`]).
|
||||
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Width {
|
||||
/// Comportamiento por defecto, aplica los anchos máximos predefinidos para cada punto de
|
||||
/// ruptura. Por debajo del menor punto de ruptura ocupa el 100% del ancho disponible.
|
||||
/// Comportamiento por defecto, aplica los anchos máximos predefinidos para cada punto de corte.
|
||||
/// Por debajo del menor punto de corte ocupa el 100% del ancho disponible.
|
||||
#[default]
|
||||
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.
|
||||
/// Aplica los anchos máximos predefinidos a partir del punto de corte indicado. Por debajo de
|
||||
/// ese punto de corte ocupa el 100% del ancho disponible.
|
||||
From(Breakpoint),
|
||||
/// Ocupa el 100% del ancho disponible siempre.
|
||||
Fluid,
|
||||
|
|
@ -73,7 +73,7 @@ impl Width {
|
|||
|
||||
/// 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`.
|
||||
/// El nombre del punto de corte se resuelve en el tema activo de `cx`.
|
||||
#[inline]
|
||||
pub fn push_to(self, cx: &Context, classes: &mut String) {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -112,28 +112,28 @@ 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 corte ([`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.
|
||||
/// Alineación al inicio a partir del punto de corte indicado.
|
||||
StartAt(Breakpoint),
|
||||
/// Alineación al inicio por defecto, y al final a partir de un punto de ruptura válido.
|
||||
/// Alineación al inicio por defecto, y al final a partir de un punto de corte válido.
|
||||
StartAndEnd(Breakpoint),
|
||||
/// Alineación al final.
|
||||
End,
|
||||
/// Alineación al final a partir del punto de ruptura indicado.
|
||||
/// Alineación al final a partir del punto de corte indicado.
|
||||
EndAt(Breakpoint),
|
||||
/// Alineación al final por defecto, y al inicio a partir de un punto de ruptura válido.
|
||||
/// Alineación al final por defecto, y al inicio a partir de un punto de corte válido.
|
||||
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`.
|
||||
/// El nombre del punto de corte se resuelve en el tema activo de `cx`.
|
||||
#[inline]
|
||||
pub fn push_to(self, cx: &Context, classes: &mut String) {
|
||||
const MENU: &str = "dropdown-menu";
|
||||
|
|
|
|||
|
|
@ -8,16 +8,18 @@ const TOGGLE_OFFCANVAS: &str = "offcanvas";
|
|||
|
||||
const EXTRA_LAYOUT: &str = "bootsier.navbar.layout";
|
||||
const EXTRA_POSITION: &str = "bootsier.navbar.position";
|
||||
const EXTRA_EXPAND: &str = "bootsier.navbar.expand";
|
||||
|
||||
/// Extensión de Bootsier para [`Navbar`](crate::theme::bs::Navbar).
|
||||
/// Extensión de Bootsier para [`Navbar`].
|
||||
///
|
||||
/// Permite mostrar enlaces, menús y una marca de identidad en distintas disposiciones (simples, con
|
||||
/// botón de despliegue o dentro de un [`Offcanvas`](crate::theme::bs::Offcanvas)), controladas por
|
||||
/// [`navbar::Layout`](crate::theme::bs::navbar::Layout). También puede fijarse en la parte superior
|
||||
/// o inferior del documento mediante [`navbar::Position`](crate::theme::bs::navbar::Position), y
|
||||
/// definir a partir de qué punto de ruptura deja de colapsar con
|
||||
/// [`with_expand()`](Self::with_expand).
|
||||
/// botón de despliegue o dentro de un [`Offcanvas`]), controladas por [`navbar::Layout`]. También
|
||||
/// puede fijarse en la parte superior o inferior del documento mediante [`navbar::Position`]. El
|
||||
/// punto de corte a partir del cual deja de colapsar se define con [`Navbar::with_expand()`].
|
||||
///
|
||||
/// [`Navbar`]: crate::theme::bs::Navbar
|
||||
/// [`Offcanvas`]: crate::theme::bs::Offcanvas
|
||||
/// [`navbar::Layout`]: crate::theme::bs::navbar::Layout
|
||||
/// [`navbar::Position`]: crate::theme::bs::navbar::Position
|
||||
///
|
||||
/// # Ejemplos
|
||||
///
|
||||
|
|
@ -42,7 +44,6 @@ 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_item(bs::navbar::Item::nav(
|
||||
/// bs::Nav::new()
|
||||
/// .with_item(bs::nav::Item::link(Lc::n("Home"), "/"))
|
||||
|
|
@ -151,9 +152,6 @@ pub trait NavbarBootsier {
|
|||
/// Crea una barra de navegación con **marca de identidad** y contenido en **offcanvas**.
|
||||
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;
|
||||
|
||||
/// Define dónde se mostrará la barra de navegación dentro del documento.
|
||||
fn with_position(self, position: bs::navbar::Position) -> Self;
|
||||
}
|
||||
|
|
@ -187,11 +185,6 @@ impl NavbarBootsier for Navbar {
|
|||
navbar
|
||||
}
|
||||
|
||||
fn with_expand(mut self, bp: Breakpoint) -> Self {
|
||||
self.alter_prop(PropsOp::set_extra(EXTRA_EXPAND, bp));
|
||||
self
|
||||
}
|
||||
|
||||
fn with_position(mut self, position: bs::navbar::Position) -> Self {
|
||||
self.alter_prop(PropsOp::set_extra(EXTRA_POSITION, position));
|
||||
self
|
||||
|
|
@ -200,15 +193,11 @@ impl NavbarBootsier for Navbar {
|
|||
|
||||
// **< Navbar SETUP >*******************************************************************************
|
||||
|
||||
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);
|
||||
pub(crate) fn setup(navbar: &mut Navbar) {
|
||||
let position = navbar
|
||||
.props()
|
||||
.extra_or(EXTRA_POSITION, bs::navbar::Position::default());
|
||||
let mut classes = String::new();
|
||||
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));
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use crate::theme::*;
|
|||
/// - Se puede configurar el borde de la ventana desde el que se desliza el panel
|
||||
/// ([`with_placement()`](Self::with_placement)).
|
||||
/// - Encabezado con título ([`with_title()`](Self::with_title)) y **botón de cierre** integrado.
|
||||
/// - Puede cambiar su comportamiento a partir de un punto de ruptura
|
||||
/// - Puede cambiar su comportamiento a partir de un punto de corte
|
||||
/// ([`with_breakpoint()`](Self::with_breakpoint)).
|
||||
/// - Asocia título y controles de accesibilidad a un identificador único y expone atributos
|
||||
/// adecuados para lectores de pantalla y navegación por teclado.
|
||||
|
|
@ -47,7 +47,7 @@ pub struct Offcanvas {
|
|||
props: Props,
|
||||
/// Devuelve el título del panel.
|
||||
title: Lc,
|
||||
/// Devuelve el punto de ruptura configurado para cambiar el comportamiento del panel.
|
||||
/// Devuelve el punto de corte configurado para cambiar el comportamiento del panel.
|
||||
breakpoint: Breakpoint,
|
||||
/// Devuelve el comportamiento configurado para la capa de fondo.
|
||||
backdrop: bs::offcanvas::Backdrop,
|
||||
|
|
@ -112,7 +112,7 @@ impl Offcanvas {
|
|||
self
|
||||
}
|
||||
|
||||
/// Establece el punto de ruptura a partir del cual cambia el comportamiento del panel.
|
||||
/// Establece el punto de corte a partir del cual cambia el comportamiento del panel.
|
||||
///
|
||||
/// - **Por debajo** de ese tamaño de pantalla, el componente actúa como panel deslizante
|
||||
/// ([`Offcanvas`]).
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Define clases para aplicar en componentes del tema.
|
||||
//!
|
||||
//! Incluyen puntos de ruptura, colores y niveles de opacidad, escalas de tamaño y lados, necesarios
|
||||
//! para crear determinadas clases del tema:
|
||||
//! Incluyen colores y niveles de opacidad, escalas de tamaño y lados, necesarios para crear
|
||||
//! determinadas clases del tema:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use pagetop_bootsier::theme::*;
|
||||
|
|
|
|||
|
|
@ -50,12 +50,22 @@ async fn navbar_expands_at_md_by_default_and_at_the_chosen_breakpoint() {
|
|||
let mut navbar = bs::Navbar::simple().with_item(item());
|
||||
let html = navbar.render(&mut cx()).await.into_string();
|
||||
assert!(html.contains("navbar-expand-md"));
|
||||
// The expansion class comes from the `Navbar` component only, so it is not duplicated.
|
||||
assert_eq!(html.matches("navbar-expand").count(), 1);
|
||||
|
||||
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"));
|
||||
|
||||
// Bootstrap needs a plain `navbar-expand` to keep the bar always expanded.
|
||||
let mut navbar = bs::Navbar::simple()
|
||||
.with_expand(Breakpoint::Xs)
|
||||
.with_item(item());
|
||||
let html = navbar.render(&mut cx()).await.into_string();
|
||||
assert!(html.contains("navbar-expand"));
|
||||
assert!(!html.contains("navbar-expand-"));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ use crate::prelude::*;
|
|||
/// Componente para crear una **barra de navegación**.
|
||||
///
|
||||
/// Permite mostrar enlaces, menús desplegables ([`nav::Item::dropdown()`]) y una marca de
|
||||
/// identidad, en distintas disposiciones controladas por [`navbar::Layout`].
|
||||
/// identidad, en distintas disposiciones controladas por [`navbar::Layout`]. El punto de corte a
|
||||
/// partir del cual deja de colapsar se define con [`with_expand()`](Self::with_expand).
|
||||
///
|
||||
/// Si no contiene elementos, el componente **no se renderiza**.
|
||||
///
|
||||
|
|
@ -23,11 +24,13 @@ use crate::prelude::*;
|
|||
/// ));
|
||||
/// ```
|
||||
///
|
||||
/// Barra **colapsable**, con botón de despliegue:
|
||||
/// Barra **colapsable**, con botón de despliegue, que muestra su contenido en línea a partir de un
|
||||
/// punto de corte (por defecto, [`Breakpoint::Md`]):
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use pagetop::prelude::*;
|
||||
/// let navbar = Navbar::simple_toggle()
|
||||
/// .with_expand(Breakpoint::Lg)
|
||||
/// .with_item(navbar::Item::nav(
|
||||
/// Nav::new()
|
||||
/// .with_item(nav::Item::link(Lc::n("Home"), "/"))
|
||||
|
|
@ -81,6 +84,10 @@ pub struct Navbar {
|
|||
props: Props,
|
||||
/// Devuelve la disposición configurada para la barra de navegación.
|
||||
layout: navbar::Layout,
|
||||
/// Devuelve el punto de corte a partir del cual la barra deja de colapsar.
|
||||
#[default(Breakpoint::Md)]
|
||||
#[getters(copy)]
|
||||
expand: Breakpoint,
|
||||
/// Devuelve la lista de contenidos.
|
||||
items: Children,
|
||||
}
|
||||
|
|
@ -101,6 +108,12 @@ impl Component for Navbar {
|
|||
// de despliegue lo necesita para referenciar ese contenido colapsable con `aria-controls`
|
||||
// si el *layout* lo incluye.
|
||||
self.alter_prop(PropsOp::ensure_id(cx.build_id::<Self>(1)));
|
||||
|
||||
let class: CowStr = match self.expand().resolved(cx) {
|
||||
Some(entry) => util::join!("navbar-expand-", entry.name).into(),
|
||||
None => "navbar-expand".into(),
|
||||
};
|
||||
self.alter_prop(PropsOp::prepend_classes(class));
|
||||
self.alter_prop(PropsOp::prepend_classes("navbar"));
|
||||
}
|
||||
|
||||
|
|
@ -218,6 +231,17 @@ impl Navbar {
|
|||
self
|
||||
}
|
||||
|
||||
/// Define a partir de qué punto de corte ([`Breakpoint`]) la barra de navegación deja de
|
||||
/// colapsar y muestra su contenido en línea.
|
||||
///
|
||||
/// Por debajo de ese punto de corte, en las disposiciones con botón de despliegue el contenido
|
||||
/// queda oculto tras el botón. Con [`Breakpoint::Xs`] la barra nunca colapsa. Por defecto es
|
||||
/// [`Breakpoint::Md`].
|
||||
pub fn with_expand(mut self, bp: Breakpoint) -> Self {
|
||||
self.expand = bp;
|
||||
self
|
||||
}
|
||||
|
||||
/// Añade un nuevo contenido a la barra de navegación o modifica la lista de contenidos de la
|
||||
/// barra con una operación [`TypedOp`].
|
||||
///
|
||||
|
|
|
|||
|
|
@ -26,3 +26,45 @@ async fn push_end_adds_an_automatic_start_margin() {
|
|||
assert!(html.contains("_flex-item-offset_auto_"));
|
||||
assert!(assets.contains("_flex-item-offset_auto_{margin-inline-start:auto}"));
|
||||
}
|
||||
|
||||
// **< Navbar::with_expand >************************************************************************
|
||||
|
||||
#[pagetop::test]
|
||||
async fn expand_is_md_by_default_and_can_be_set() {
|
||||
assert_eq!(Navbar::simple().expand(), Breakpoint::Md);
|
||||
assert_eq!(
|
||||
Navbar::simple().with_expand(Breakpoint::Lg).expand(),
|
||||
Breakpoint::Lg
|
||||
);
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn expand_class_is_md_by_default() {
|
||||
let mut navbar = Navbar::simple_toggle().with_item(navbar::Item::nav(one_link_nav()));
|
||||
let html = navbar.render(&mut Context::default()).await.into_string();
|
||||
|
||||
assert!(html.contains("navbar-expand-md"));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn expand_class_uses_the_breakpoint_name() {
|
||||
let mut navbar = Navbar::simple_toggle()
|
||||
.with_expand(Breakpoint::Xl)
|
||||
.with_item(navbar::Item::nav(one_link_nav()));
|
||||
let html = navbar.render(&mut Context::default()).await.into_string();
|
||||
|
||||
assert!(html.contains("navbar-expand-xl"));
|
||||
assert!(!html.contains("navbar-expand-md"));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn expand_class_has_no_name_without_a_breakpoint_width() {
|
||||
// `Xs` has no minimum width, so the class carries no breakpoint name.
|
||||
let mut navbar = Navbar::simple_toggle()
|
||||
.with_expand(Breakpoint::Xs)
|
||||
.with_item(navbar::Item::nav(one_link_nav()));
|
||||
let html = navbar.render(&mut Context::default()).await.into_string();
|
||||
|
||||
assert!(html.contains("navbar-expand"));
|
||||
assert!(!html.contains("navbar-expand-"));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue