✨ [bootsier] Nuevo componente Dropdown
This commit is contained in:
parent
352454789f
commit
fb38da4e8c
5 changed files with 221 additions and 0 deletions
|
|
@ -20,6 +20,10 @@ pub use offcanvas::{
|
|||
pub mod navbar;
|
||||
pub use navbar::{Navbar, NavbarContent, NavbarToggler};
|
||||
|
||||
// Dropdown.
|
||||
pub mod dropdown;
|
||||
pub use dropdown::Dropdown;
|
||||
|
||||
/// Define los puntos de interrupción (*breakpoints*) usados por Bootstrap para diseño responsivo.
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
|
|
|
|||
5
packages/pagetop-bootsier/src/bs/dropdown.rs
Normal file
5
packages/pagetop-bootsier/src/bs/dropdown.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod component;
|
||||
pub use component::Dropdown;
|
||||
|
||||
mod item;
|
||||
pub use item::Item;
|
||||
99
packages/pagetop-bootsier/src/bs/dropdown/component.rs
Normal file
99
packages/pagetop-bootsier/src/bs/dropdown/component.rs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::dropdown;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Dropdown {
|
||||
id : OptionId,
|
||||
classes: OptionClasses,
|
||||
items : Children,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Dropdown {
|
||||
fn new() -> Self {
|
||||
Dropdown::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, _cx: &mut Context) {
|
||||
self.alter_classes(ClassesOp::Prepend, "dropdown");
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let items = self.items().render(cx);
|
||||
if items.is_empty() {
|
||||
return PrepareMarkup::None;
|
||||
}
|
||||
|
||||
PrepareMarkup::With(html! {
|
||||
div id=[self.id()] class=[self.classes().get()] {
|
||||
button
|
||||
type="button"
|
||||
class="btn btn-secondary dropdown-toggle"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
{
|
||||
("Dropdown button")
|
||||
}
|
||||
ul class="dropdown-menu" {
|
||||
li {
|
||||
a class="dropdown-item" href="#" {
|
||||
("Action")
|
||||
}
|
||||
}
|
||||
li {
|
||||
a class="dropdown-item" href="#" {
|
||||
("Another action")
|
||||
}
|
||||
}
|
||||
li {
|
||||
a class="dropdown-item" href="#" {
|
||||
("Something else here")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Dropdown {
|
||||
// Dropdown BUILDER.
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_id(mut self, id: impl Into<String>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_classes(mut self, op: ClassesOp, classes: impl Into<String>) -> Self {
|
||||
self.classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_item(mut self, item: dropdown::Item) -> Self {
|
||||
self.items.add(Child::with(item));
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_builder]
|
||||
pub fn with_items(mut self, op: TypedOp<dropdown::Item>) -> Self {
|
||||
self.items.alter_typed(op);
|
||||
self
|
||||
}
|
||||
|
||||
// Dropdown GETTERS.
|
||||
|
||||
pub fn classes(&self) -> &OptionClasses {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
pub fn items(&self) -> &Children {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
109
packages/pagetop-bootsier/src/bs/dropdown/item.rs
Normal file
109
packages/pagetop-bootsier/src/bs/dropdown/item.rs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
type Label = L10n;
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
pub enum ItemType {
|
||||
#[default]
|
||||
Void,
|
||||
Label(Label),
|
||||
Link(Label, FnContextualPath),
|
||||
LinkBlank(Label, FnContextualPath),
|
||||
}
|
||||
|
||||
// Item.
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Item {
|
||||
item_type: ItemType,
|
||||
}
|
||||
|
||||
impl ComponentTrait for Item {
|
||||
fn new() -> Self {
|
||||
Item::default()
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let description: Option<String> = None;
|
||||
|
||||
// Obtiene la URL actual desde `cx.request`.
|
||||
let current_path = cx.request().path();
|
||||
|
||||
match self.item_type() {
|
||||
ItemType::Void => PrepareMarkup::None,
|
||||
ItemType::Label(label) => PrepareMarkup::With(html! {
|
||||
li class="dropdown-item" {
|
||||
span title=[description] {
|
||||
//(left_icon)
|
||||
(label.escaped(cx.langid()))
|
||||
//(right_icon)
|
||||
}
|
||||
}
|
||||
}),
|
||||
ItemType::Link(label, path) => {
|
||||
let item_path = path(cx);
|
||||
let (class, aria) = if item_path == current_path {
|
||||
("dropdown-item active", Some("page"))
|
||||
} else {
|
||||
("dropdown-item", None)
|
||||
};
|
||||
PrepareMarkup::With(html! {
|
||||
li class=(class) aria-current=[aria] {
|
||||
a class="nav-link" href=(item_path) title=[description] {
|
||||
//(left_icon)
|
||||
(label.escaped(cx.langid()))
|
||||
//(right_icon)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
ItemType::LinkBlank(label, path) => {
|
||||
let item_path = path(cx);
|
||||
let (class, aria) = if item_path == current_path {
|
||||
("dropdown-item active", Some("page"))
|
||||
} else {
|
||||
("dropdown-item", None)
|
||||
};
|
||||
PrepareMarkup::With(html! {
|
||||
li class=(class) aria-current=[aria] {
|
||||
a class="nav-link" href=(item_path) title=[description] target="_blank" {
|
||||
//(left_icon)
|
||||
(label.escaped(cx.langid()))
|
||||
//(right_icon)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn label(label: L10n) -> Self {
|
||||
Item {
|
||||
item_type: ItemType::Label(label),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn link(label: L10n, path: FnContextualPath) -> Self {
|
||||
Item {
|
||||
item_type: ItemType::Link(label, path),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn link_blank(label: L10n, path: FnContextualPath) -> Self {
|
||||
Item {
|
||||
item_type: ItemType::LinkBlank(label, path),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
// Item GETTERS.
|
||||
|
||||
pub fn item_type(&self) -> &ItemType {
|
||||
&self.item_type
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
use crate::bs::Dropdown;
|
||||
|
||||
type Label = L10n;
|
||||
|
||||
#[derive(AutoDefault)]
|
||||
|
|
@ -9,6 +11,7 @@ pub enum ItemType {
|
|||
Label(Label),
|
||||
Link(Label, FnContextualPath),
|
||||
LinkBlank(Label, FnContextualPath),
|
||||
Dropdown(Typed<Dropdown>),
|
||||
}
|
||||
|
||||
// Item.
|
||||
|
|
@ -75,6 +78,7 @@ impl ComponentTrait for Item {
|
|||
}
|
||||
})
|
||||
}
|
||||
ItemType::Dropdown(menu) => PrepareMarkup::With(html! { (menu.render(cx)) }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue