✨ (base): Implementa Navbar con funcionalidad base

Añade `Navbar::with_position()` y `navbar::Position` al núcleo, con las
clases de Basic para barras fijas y pegajosas, y `navbar::Item::form()`
para mostrar un formulario dentro de la barra.

Las barras sin botón de despliegue (`Simple` y `SimpleBrandLeft`) ya no
colapsan: el punto de corte no les afecta y su menú se mantiene en
línea, con salto de línea si no cabe. En Bootsier usan `navbar-expand` y
`SimpleBrandLeft` agrupa los contenidos junto a la marca.
This commit is contained in:
Manuel Cillero 2026-09-21 16:27:44 +02:00
parent f8f023b513
commit c47724bb68
14 changed files with 1298 additions and 209 deletions

View file

@ -14,6 +14,23 @@ async fn is_not_rendered_when_empty() {
assert!(html.is_empty());
}
// **< navbar::Item::form >*************************************************************************
#[pagetop::test]
async fn item_form_renders_the_form() {
let mut navbar = Navbar::simple().with_item(navbar::Item::form(
Form::new()
.with_id("search")
.with_action("/search")
.with_child(Button::submit(Lc::n("Go"))),
));
let html = navbar.render(&mut Context::default()).await.into_string();
assert!(html.contains(r#"<form"#));
assert!(html.contains(r#"id="search""#));
assert!(html.contains("Go"));
}
// **< Navbar + FlexItem::push_end >****************************************************************
#[pagetop::test]
@ -27,6 +44,36 @@ async fn push_end_adds_an_automatic_start_margin() {
assert!(assets.contains("_flex-item-offset_auto_{margin-inline-start:auto}"));
}
// **< Navbar::with_position >**********************************************************************
#[pagetop::test]
async fn position_is_static_by_default_and_adds_no_class() {
assert_eq!(Navbar::simple().position(), navbar::Position::Static);
let mut navbar = Navbar::simple().with_item(navbar::Item::nav(one_link_nav()));
let html = navbar.render(&mut Context::default()).await.into_string();
assert!(!html.contains("fixed-"));
assert!(!html.contains("sticky-"));
}
#[pagetop::test]
async fn position_adds_its_class() {
for (position, class) in [
(navbar::Position::FixedTop, "fixed-top"),
(navbar::Position::FixedBottom, "fixed-bottom"),
(navbar::Position::StickyTop, "sticky-top"),
(navbar::Position::StickyBottom, "sticky-bottom"),
] {
let mut navbar = Navbar::simple()
.with_position(position)
.with_item(navbar::Item::nav(one_link_nav()));
let html = navbar.render(&mut Context::default()).await.into_string();
assert!(html.contains(class), "missing `{class}` in {html}");
}
}
// **< Navbar::with_expand >************************************************************************
#[pagetop::test]