📝 Repasa doc de Dropdown, Nav y Offcanvas
This commit is contained in:
parent
749e182619
commit
93804721e1
8 changed files with 124 additions and 108 deletions
|
|
@ -6,6 +6,23 @@
|
||||||
//!
|
//!
|
||||||
//! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y
|
//! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y
|
||||||
//! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n).
|
//! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n).
|
||||||
|
//!
|
||||||
|
//! # Ejemplo
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! # use pagetop::prelude::*;
|
||||||
|
//! # use pagetop_bootsier::prelude::*;
|
||||||
|
//! let dd = Dropdown::new()
|
||||||
|
//! .with_title(L10n::n("Menu"))
|
||||||
|
//! .with_button_color(ButtonColor::Background(Color::Secondary))
|
||||||
|
//! .with_auto_close(dropdown::AutoClose::ClickableInside)
|
||||||
|
//! .with_direction(dropdown::Direction::Dropend)
|
||||||
|
//! .add_item(dropdown::Item::link(L10n::n("Home"), |_| "/"))
|
||||||
|
//! .add_item(dropdown::Item::link_blank(L10n::n("External"), |_| "https://www.google.es"))
|
||||||
|
//! .add_item(dropdown::Item::divider())
|
||||||
|
//! .add_item(dropdown::Item::header(L10n::n("User session")))
|
||||||
|
//! .add_item(dropdown::Item::button(L10n::n("Sign out")));
|
||||||
|
//! ```
|
||||||
|
|
||||||
mod props;
|
mod props;
|
||||||
pub use props::{AutoClose, Direction, MenuAlign, MenuPosition};
|
pub use props::{AutoClose, Direction, MenuAlign, MenuPosition};
|
||||||
|
|
|
||||||
|
|
@ -17,22 +17,8 @@ use crate::LOCALES_BOOTSIER;
|
||||||
/// cuenta **el título** (si no existe le asigna uno por defecto) y **la lista de elementos**; el
|
/// cuenta **el título** (si no existe le asigna uno por defecto) y **la lista de elementos**; el
|
||||||
/// resto de propiedades no afectarán a su representación en [`Nav`].
|
/// resto de propiedades no afectarán a su representación en [`Nav`].
|
||||||
///
|
///
|
||||||
/// # Ejemplo
|
/// Ver ejemplo en el módulo [`dropdown`].
|
||||||
///
|
/// Si no contiene elementos, el componente **no se renderiza**.
|
||||||
/// ```rust
|
|
||||||
/// # use pagetop::prelude::*;
|
|
||||||
/// # use pagetop_bootsier::prelude::*;
|
|
||||||
/// let dd = Dropdown::new()
|
|
||||||
/// .with_title(L10n::n("Menu"))
|
|
||||||
/// .with_button_color(ButtonColor::Background(Color::Secondary))
|
|
||||||
/// .with_auto_close(dropdown::AutoClose::ClickableInside)
|
|
||||||
/// .with_direction(dropdown::Direction::Dropend)
|
|
||||||
/// .add_item(dropdown::Item::link(L10n::n("Home"), |_| "/"))
|
|
||||||
/// .add_item(dropdown::Item::link_blank(L10n::n("External"), |_| "https://www.google.es"))
|
|
||||||
/// .add_item(dropdown::Item::divider())
|
|
||||||
/// .add_item(dropdown::Item::header(L10n::n("User session")))
|
|
||||||
/// .add_item(dropdown::Item::button(L10n::n("Sign out")));
|
|
||||||
/// ```
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[derive(AutoDefault)]
|
#[derive(AutoDefault)]
|
||||||
pub struct Dropdown {
|
pub struct Dropdown {
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ impl Component for Item {
|
||||||
} => {
|
} => {
|
||||||
let path = path(cx);
|
let path = path(cx);
|
||||||
let current_path = cx.request().map(|request| request.path());
|
let current_path = cx.request().map(|request| request.path());
|
||||||
let is_current = !*disabled && current_path.map_or(false, |p| p == path);
|
let is_current = !*disabled && (current_path == Some(path));
|
||||||
|
|
||||||
let mut classes = "dropdown-item".to_string();
|
let mut classes = "dropdown-item".to_string();
|
||||||
if is_current {
|
if is_current {
|
||||||
|
|
@ -274,7 +274,7 @@ impl Item {
|
||||||
&self.classes
|
&self.classes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Devuelve el tipo de elemento representado por este elemento.
|
/// Devuelve el tipo de elemento representado.
|
||||||
pub fn item_kind(&self) -> &ItemKind {
|
pub fn item_kind(&self) -> &ItemKind {
|
||||||
&self.item_kind
|
&self.item_kind
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,26 @@
|
||||||
//!
|
//!
|
||||||
//! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y
|
//! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y
|
||||||
//! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n).
|
//! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n).
|
||||||
|
//!
|
||||||
|
//! # Ejemplo
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! # use pagetop::prelude::*;
|
||||||
|
//! # use pagetop_bootsier::prelude::*;
|
||||||
|
//! let nav = Nav::tabs()
|
||||||
|
//! .with_layout(nav::Layout::End)
|
||||||
|
//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/"))
|
||||||
|
//! .add_item(nav::Item::link_blank(L10n::n("External"), |_| "https://www.google.es"))
|
||||||
|
//! .add_item(nav::Item::dropdown(
|
||||||
|
//! Dropdown::new()
|
||||||
|
//! .with_title(L10n::n("Options"))
|
||||||
|
//! .with_items(TypedOp::AddMany(vec![
|
||||||
|
//! Typed::with(dropdown::Item::link(L10n::n("Action"), |_| "/action")),
|
||||||
|
//! Typed::with(dropdown::Item::link(L10n::n("Another action"), |_| "/another")),
|
||||||
|
//! ])),
|
||||||
|
//! ))
|
||||||
|
//! .add_item(nav::Item::link_disabled(L10n::n("Disabled"), |_| "#"));
|
||||||
|
//! ```
|
||||||
|
|
||||||
mod props;
|
mod props;
|
||||||
pub use props::{Kind, Layout};
|
pub use props::{Kind, Layout};
|
||||||
|
|
|
||||||
|
|
@ -8,25 +8,8 @@ use crate::prelude::*;
|
||||||
/// como *pestañas* (`Tabs`), *botones* (`Pills`) o *subrayado* (`Underline`). También permite
|
/// como *pestañas* (`Tabs`), *botones* (`Pills`) o *subrayado* (`Underline`). También permite
|
||||||
/// controlar su distribución y orientación ([`nav::Layout`](crate::theme::nav::Layout)).
|
/// controlar su distribución y orientación ([`nav::Layout`](crate::theme::nav::Layout)).
|
||||||
///
|
///
|
||||||
/// # Ejemplo
|
/// Ver ejemplo en el módulo [`nav`].
|
||||||
///
|
/// Si no contiene elementos, el componente **no se renderiza**.
|
||||||
/// ```rust
|
|
||||||
/// # use pagetop::prelude::*;
|
|
||||||
/// # use pagetop_bootsier::prelude::*;
|
|
||||||
/// let nav = Nav::tabs()
|
|
||||||
/// .with_layout(nav::Layout::End)
|
|
||||||
/// .add_item(nav::Item::link(L10n::n("Home"), |_| "/"))
|
|
||||||
/// .add_item(nav::Item::link_blank(L10n::n("External"), |_| "https://www.google.es"))
|
|
||||||
/// .add_item(nav::Item::dropdown(
|
|
||||||
/// Dropdown::new()
|
|
||||||
/// .with_title(L10n::n("Options"))
|
|
||||||
/// .with_items(TypedOp::AddMany(vec![
|
|
||||||
/// Typed::with(dropdown::Item::link(L10n::n("Action"), |_| "/action")),
|
|
||||||
/// Typed::with(dropdown::Item::link(L10n::n("Another action"), |_| "/another")),
|
|
||||||
/// ])),
|
|
||||||
/// ))
|
|
||||||
/// .add_item(nav::Item::link_disabled(L10n::n("Disabled"), |_| "#"));
|
|
||||||
/// ```
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[derive(AutoDefault)]
|
#[derive(AutoDefault)]
|
||||||
pub struct Nav {
|
pub struct Nav {
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ impl Component for Item {
|
||||||
|
|
||||||
ItemKind::Label(label) => PrepareMarkup::With(html! {
|
ItemKind::Label(label) => PrepareMarkup::With(html! {
|
||||||
li id=[self.id()] class=[self.classes().get()] {
|
li id=[self.id()] class=[self.classes().get()] {
|
||||||
span {
|
span class="nav-link disabled" aria-disabled="true" {
|
||||||
(label.using(cx))
|
(label.using(cx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +86,7 @@ impl Component for Item {
|
||||||
} => {
|
} => {
|
||||||
let path = path(cx);
|
let path = path(cx);
|
||||||
let current_path = cx.request().map(|request| request.path());
|
let current_path = cx.request().map(|request| request.path());
|
||||||
let is_current = !*disabled && current_path.map_or(false, |p| p == path);
|
let is_current = !*disabled && (current_path == Some(path));
|
||||||
|
|
||||||
let mut classes = "nav-link".to_string();
|
let mut classes = "nav-link".to_string();
|
||||||
if is_current {
|
if is_current {
|
||||||
|
|
@ -250,7 +250,7 @@ impl Item {
|
||||||
&self.classes
|
&self.classes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Devuelve el tipo de elemento representado por este elemento.
|
/// Devuelve el tipo de elemento representado.
|
||||||
pub fn item_kind(&self) -> &ItemKind {
|
pub fn item_kind(&self) -> &ItemKind {
|
||||||
&self.item_kind
|
&self.item_kind
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,24 @@
|
||||||
//! Definiciones para crear paneles laterales deslizantes [`Offcanvas`].
|
//! Definiciones para crear paneles laterales deslizantes [`Offcanvas`].
|
||||||
|
//!
|
||||||
|
//! # Ejemplo
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! # use pagetop::prelude::*;
|
||||||
|
//! # use pagetop_bootsier::prelude::*;
|
||||||
|
//! let panel = Offcanvas::new()
|
||||||
|
//! .with_id("offcanvas_example")
|
||||||
|
//! .with_title(L10n::n("Offcanvas title"))
|
||||||
|
//! .with_placement(offcanvas::Placement::End)
|
||||||
|
//! .with_backdrop(offcanvas::Backdrop::Enabled)
|
||||||
|
//! .with_body_scroll(offcanvas::BodyScroll::Enabled)
|
||||||
|
//! .with_visibility(offcanvas::Visibility::Default)
|
||||||
|
//! .add_child(Dropdown::new()
|
||||||
|
//! .with_button_title(L10n::n("Menu"))
|
||||||
|
//! .add_item(dropdown::Item::label(L10n::n("Label")))
|
||||||
|
//! .add_item(dropdown::Item::link_blank(L10n::n("Google"), |_| "https://www.google.es"))
|
||||||
|
//! .add_item(dropdown::Item::link(L10n::n("Sign out"), |_| "/signout"))
|
||||||
|
//! );
|
||||||
|
//! ```
|
||||||
|
|
||||||
mod props;
|
mod props;
|
||||||
pub use props::{Backdrop, BodyScroll, Placement, Visibility};
|
pub use props::{Backdrop, BodyScroll, Placement, Visibility};
|
||||||
|
|
|
||||||
|
|
@ -18,27 +18,9 @@ use crate::LOCALES_BOOTSIER;
|
||||||
/// ([`with_breakpoint()`](Self::with_breakpoint)).
|
/// ([`with_breakpoint()`](Self::with_breakpoint)).
|
||||||
/// - Asocia título y controles de accesibilidad a un identificador único y expone atributos
|
/// - Asocia título y controles de accesibilidad a un identificador único y expone atributos
|
||||||
/// adecuados para lectores de pantalla y navegación por teclado.
|
/// adecuados para lectores de pantalla y navegación por teclado.
|
||||||
/// - **No se renderiza** si no tiene contenido.
|
|
||||||
///
|
///
|
||||||
/// # Ejemplo
|
/// Ver ejemplo en el módulo [`offcanvas`].
|
||||||
///
|
/// Si no contiene elementos, el componente **no se renderiza**.
|
||||||
/// ```rust
|
|
||||||
/// # use pagetop::prelude::*;
|
|
||||||
/// # use pagetop_bootsier::prelude::*;
|
|
||||||
/// let panel = Offcanvas::new()
|
|
||||||
/// .with_id("offcanvas_example")
|
|
||||||
/// .with_title(L10n::n("Offcanvas title"))
|
|
||||||
/// .with_placement(offcanvas::Placement::End)
|
|
||||||
/// .with_backdrop(offcanvas::Backdrop::Enabled)
|
|
||||||
/// .with_body_scroll(offcanvas::BodyScroll::Enabled)
|
|
||||||
/// .with_visibility(offcanvas::Visibility::Default)
|
|
||||||
/// .add_child(Dropdown::new()
|
|
||||||
/// .with_button_title(L10n::n("Menu"))
|
|
||||||
/// .add_item(dropdown::Item::label(L10n::n("Label")))
|
|
||||||
/// .add_item(dropdown::Item::link_blank(L10n::n("Google"), |_| "https://www.google.es"))
|
|
||||||
/// .add_item(dropdown::Item::link(L10n::n("Sign out"), |_| "/signout"))
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[derive(AutoDefault)]
|
#[derive(AutoDefault)]
|
||||||
pub struct Offcanvas {
|
pub struct Offcanvas {
|
||||||
|
|
@ -84,54 +66,7 @@ impl Component for Offcanvas {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||||
let body = self.children().render(cx);
|
PrepareMarkup::With(self.render_offcanvas(cx, None))
|
||||||
if body.is_empty() {
|
|
||||||
return PrepareMarkup::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let id = cx.required_id::<Self>(self.id());
|
|
||||||
let id_label = join!(id, "-label");
|
|
||||||
let id_target = join!("#", id);
|
|
||||||
|
|
||||||
let body_scroll = match self.body_scroll() {
|
|
||||||
offcanvas::BodyScroll::Disabled => None,
|
|
||||||
offcanvas::BodyScroll::Enabled => Some("true"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let backdrop = match self.backdrop() {
|
|
||||||
offcanvas::Backdrop::Disabled => Some("false"),
|
|
||||||
offcanvas::Backdrop::Enabled => None,
|
|
||||||
offcanvas::Backdrop::Static => Some("static"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let title = self.title().using(cx);
|
|
||||||
|
|
||||||
PrepareMarkup::With(html! {
|
|
||||||
div
|
|
||||||
id=(id)
|
|
||||||
class=[self.classes().get()]
|
|
||||||
tabindex="-1"
|
|
||||||
data-bs-scroll=[body_scroll]
|
|
||||||
data-bs-backdrop=[backdrop]
|
|
||||||
aria-labelledby=(id_label)
|
|
||||||
{
|
|
||||||
div class="offcanvas-header" {
|
|
||||||
@if !title.is_empty() {
|
|
||||||
h5 class="offcanvas-title" id=(id_label) { (title) }
|
|
||||||
}
|
|
||||||
button
|
|
||||||
type="button"
|
|
||||||
class="btn-close"
|
|
||||||
data-bs-dismiss="offcanvas"
|
|
||||||
data-bs-target=(id_target)
|
|
||||||
aria-label=[L10n::t("offcanvas_close", &LOCALES_BOOTSIER).lookup(cx)]
|
|
||||||
{}
|
|
||||||
}
|
|
||||||
div class="offcanvas-body" {
|
|
||||||
(body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -258,4 +193,59 @@ impl Offcanvas {
|
||||||
pub fn children(&self) -> &Children {
|
pub fn children(&self) -> &Children {
|
||||||
&self.children
|
&self.children
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// **< Offcanvas HELPERS >**********************************************************************
|
||||||
|
|
||||||
|
pub(crate) fn render_offcanvas(&self, cx: &mut Context, extra: Option<&Children>) -> Markup {
|
||||||
|
let body = self.children().render(cx);
|
||||||
|
let body_extra = extra.map(|c| c.render(cx)).unwrap_or_else(|| html! {});
|
||||||
|
if body.is_empty() && body_extra.is_empty() {
|
||||||
|
return html! {};
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = cx.required_id::<Self>(self.id());
|
||||||
|
let id_label = join!(id, "-label");
|
||||||
|
let id_target = join!("#", id);
|
||||||
|
|
||||||
|
let body_scroll = match self.body_scroll() {
|
||||||
|
offcanvas::BodyScroll::Disabled => None,
|
||||||
|
offcanvas::BodyScroll::Enabled => Some("true"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let backdrop = match self.backdrop() {
|
||||||
|
offcanvas::Backdrop::Disabled => Some("false"),
|
||||||
|
offcanvas::Backdrop::Enabled => None,
|
||||||
|
offcanvas::Backdrop::Static => Some("static"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let title = self.title().using(cx);
|
||||||
|
|
||||||
|
html! {
|
||||||
|
div
|
||||||
|
id=(id)
|
||||||
|
class=[self.classes().get()]
|
||||||
|
tabindex="-1"
|
||||||
|
data-bs-scroll=[body_scroll]
|
||||||
|
data-bs-backdrop=[backdrop]
|
||||||
|
aria-labelledby=(id_label)
|
||||||
|
{
|
||||||
|
div class="offcanvas-header" {
|
||||||
|
@if !title.is_empty() {
|
||||||
|
h5 class="offcanvas-title" id=(id_label) { (title) }
|
||||||
|
}
|
||||||
|
button
|
||||||
|
type="button"
|
||||||
|
class="btn-close"
|
||||||
|
data-bs-dismiss="offcanvas"
|
||||||
|
data-bs-target=(id_target)
|
||||||
|
aria-label=[L10n::t("offcanvas_close", &LOCALES_BOOTSIER).lookup(cx)]
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
div class="offcanvas-body" {
|
||||||
|
(body)
|
||||||
|
(body_extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue