use pagetop::prelude::*; use crate::theme::*; /// Componente para crear un **menú** ([`nav`]). /// /// Presenta un menú con una lista de elementos usando una vista básica, o alguna de sus variantes /// ([`nav::Kind`]) 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)). /// /// Si no contiene elementos, el componente **no se renderiza**. /// /// # Ejemplo /// /// ```rust /// use pagetop::prelude::*; /// use pagetop_bootsier::theme::*; /// /// let nav = Nav::tabs() /// .with_layout(nav::Layout::End) /// .with_item(nav::Item::link(L10n::n("Home"), |_| "/".into())) /// .with_item(nav::Item::link_blank(L10n::n("External"), |_| "https://docs.rs".into())) /// .with_item(nav::Item::dropdown( /// Dropdown::new() /// .with_title(L10n::n("Options")) /// .with_item(ChildOp::AddMany(vec![ /// dropdown::Item::link(L10n::n("Action"), |_| "/action".into()).into(), /// dropdown::Item::link(L10n::n("Another"), |_| "/another".into()).into(), /// ])), /// )) /// .with_item(nav::Item::link_disabled(L10n::n("Disabled"), |_| "#".into())); /// ``` #[derive(AutoDefault, Clone, Debug, Getters)] pub struct Nav { #[getters(skip)] id: AttrId, /// Devuelve las clases CSS asociadas al menú. classes: Classes, /// Devuelve el estilo visual seleccionado. nav_kind: nav::Kind, /// Devuelve la distribución y orientación seleccionada. nav_layout: nav::Layout, /// Devuelve la lista de elementos del menú. items: Children, } impl Component for Nav { fn new() -> Self { Self::default() } fn id(&self) -> Option { self.id.get() } fn setup(&mut self, _cx: &Context) { self.alter_classes(ClassesOp::Prepend, { let mut classes = "nav".to_string(); self.nav_kind().push_class(&mut classes); self.nav_layout().push_class(&mut classes); classes }); } fn prepare(&self, cx: &mut Context) -> Result { let items = self.items().render(cx); if items.is_empty() { return Ok(html! {}); } Ok(html! { ul id=[self.id()] class=[self.classes().get()] { (items) } }) } } impl Nav { /// Crea un `Nav` usando pestañas para los elementos (*Tabs*). pub fn tabs() -> Self { Self::default().with_kind(nav::Kind::Tabs) } /// Crea un `Nav` usando botones para los elementos (*Pills*). pub fn pills() -> Self { Self::default().with_kind(nav::Kind::Pills) } /// Crea un `Nav` usando elementos subrayados (*Underline*). pub fn underline() -> Self { Self::default().with_kind(nav::Kind::Underline) } // **< Nav BUILDER >**************************************************************************** /// Establece el identificador único (`id`) del menú. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { self.id.alter_id(id); self } /// Modifica la lista de clases CSS aplicadas al menú. #[builder_fn] pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef) -> Self { self.classes.alter_classes(op, classes); self } /// Cambia el estilo del menú (*Tabs*, *Pills*, *Underline* o *Default*). #[builder_fn] pub fn with_kind(mut self, kind: nav::Kind) -> Self { self.nav_kind = kind; self } /// Selecciona la distribución y orientación del menú. #[builder_fn] pub fn with_layout(mut self, layout: nav::Layout) -> Self { self.nav_layout = layout; self } /// Añade un nuevo elemento al menú o modifica la lista de elementos del menú con una operación /// [`ChildOp`]. /// /// # Ejemplo /// /// ```rust,ignore /// nav.with_item(nav::Item::link("Inicio", "/")); /// nav.with_item(ChildOp::AddMany(vec![ /// nav::Item::link(...).into(), /// nav::Item::link_disabled(...).into(), /// ])); /// ``` #[builder_fn] pub fn with_item(mut self, op: impl Into) -> Self { self.items.alter_child(op.into()); self } }