⚰️ [menu] Elimina implementación base de menús

This commit is contained in:
Manuel Cillero 2025-11-02 20:46:43 +01:00
parent 93804721e1
commit 41369be8c7
10 changed files with 0 additions and 1035 deletions

View file

@ -62,5 +62,3 @@ pub use poweredby::PoweredBy;
mod icon;
pub use icon::{Icon, IconKind};
pub mod menu;

View file

@ -1,17 +0,0 @@
mod menu_menu;
pub use menu_menu::Menu;
mod item;
pub use item::{Item, ItemKind};
mod submenu;
pub use submenu::Submenu;
mod megamenu;
pub use megamenu::Megamenu;
mod group;
pub use group::Group;
mod element;
pub use element::{Element, ElementType};

View file

@ -1,56 +0,0 @@
use crate::prelude::*;
type Content = Typed<Html>;
type SubmenuItems = Typed<menu::Submenu>;
#[derive(AutoDefault)]
pub enum ElementType {
#[default]
Void,
Html(Content),
Submenu(SubmenuItems),
}
#[rustfmt::skip]
#[derive(AutoDefault)]
pub struct Element {
element_type: ElementType,
}
impl Component for Element {
fn new() -> Self {
Element::default()
}
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
match self.element_type() {
ElementType::Void => PrepareMarkup::None,
ElementType::Html(content) => PrepareMarkup::With(html! {
(content.render(cx))
}),
ElementType::Submenu(submenu) => PrepareMarkup::With(html! {
(submenu.render(cx))
}),
}
}
}
impl Element {
pub fn html(content: Html) -> Self {
Element {
element_type: ElementType::Html(Content::with(content)),
}
}
pub fn submenu(submenu: menu::Submenu) -> Self {
Element {
element_type: ElementType::Submenu(SubmenuItems::with(submenu)),
}
}
// **< Element GETTERS >************************************************************************
pub fn element_type(&self) -> &ElementType {
&self.element_type
}
}

View file

@ -1,58 +0,0 @@
use crate::prelude::*;
#[rustfmt::skip]
#[derive(AutoDefault)]
pub struct Group {
id : AttrId,
elements: Children,
}
impl Component for Group {
fn new() -> Self {
Group::default()
}
fn id(&self) -> Option<String> {
self.id.get()
}
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
PrepareMarkup::With(html! {
div id=[self.id()] class="menu__group" {
(self.elements().render(cx))
}
})
}
}
impl Group {
// **< Group BUILDER >**************************************************************************
/// Establece el identificador único (`id`) del grupo.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self
}
/// Añade un nuevo elemento al menú.
pub fn add_element(mut self, element: menu::Element) -> Self {
self.elements
.alter_typed(TypedOp::Add(Typed::with(element)));
self
}
/// Modifica la lista de elementos (`children`) aplicando una operación [`TypedOp`].
#[builder_fn]
pub fn with_elements(mut self, op: TypedOp<menu::Element>) -> Self {
self.elements.alter_typed(op);
self
}
// **< Group GETTERS >**************************************************************************
/// Devuelve la lista de elementos (`children`) del grupo.
pub fn elements(&self) -> &Children {
&self.elements
}
}

View file

@ -1,185 +0,0 @@
use crate::prelude::*;
type Label = L10n;
type Content = Typed<Html>;
type SubmenuItems = Typed<menu::Submenu>;
type MegamenuGroups = Typed<menu::Megamenu>;
#[derive(AutoDefault)]
pub enum ItemKind {
#[default]
Void,
Label(Label),
Link(Label, FnPathByContext),
LinkBlank(Label, FnPathByContext),
Html(Content),
Submenu(Label, SubmenuItems),
Megamenu(Label, MegamenuGroups),
}
#[rustfmt::skip]
#[derive(AutoDefault)]
pub struct Item {
item_kind : ItemKind,
description: AttrL10n,
left_icon : Typed<Icon>,
right_icon : Typed<Icon>,
}
impl Component for Item {
fn new() -> Self {
Item::default()
}
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
let description = self.description().lookup(cx);
let left_icon = self.left_icon().render(cx);
let right_icon = self.right_icon().render(cx);
match self.item_kind() {
ItemKind::Void => PrepareMarkup::None,
ItemKind::Label(label) => PrepareMarkup::With(html! {
li class="menu__item menu__item--label" {
span title=[description] {
(left_icon)
span class="menu__label" { (label.using(cx)) }
(right_icon)
}
}
}),
ItemKind::Link(label, path) => PrepareMarkup::With(html! {
li class="menu__item menu__item--link" {
a class="menu__link" href=(path(cx)) title=[description] {
(left_icon)
span class="menu__label" { (label.using(cx)) }
(right_icon)
}
}
}),
ItemKind::LinkBlank(label, path) => PrepareMarkup::With(html! {
li class="menu__item menu__item--link" {
a class="menu__link" href=(path(cx)) title=[description] target="_blank" {
(left_icon)
span class="menu__label" { (label.using(cx)) }
(right_icon)
}
}
}),
ItemKind::Html(content) => PrepareMarkup::With(html! {
li class="menu__item menu__item--html" {
(content.render(cx))
}
}),
ItemKind::Submenu(label, submenu) => PrepareMarkup::With(html! {
li class="menu__item menu__item--children" {
button type="button" class="menu__link" title=[description] {
(left_icon)
span class="menu__label" { (label.using(cx)) }
(Icon::svg(html! {
path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" {}
}).render(cx))
}
div class="menu__children menu__children--submenu" {
(submenu.render(cx))
}
}
}),
ItemKind::Megamenu(label, megamenu) => PrepareMarkup::With(html! {
li class="menu__item menu__item--children" {
button type="button" class="menu__link" title=[description] {
(left_icon)
span class="menu__label" { (label.using(cx)) }
(Icon::svg(html! {
path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" {}
}).render(cx))
}
div class="menu__children menu__children--mega" {
(megamenu.render(cx))
}
}
}),
}
}
}
impl Item {
pub fn label(label: L10n) -> Self {
Item {
item_kind: ItemKind::Label(label),
..Default::default()
}
}
pub fn link(label: L10n, path: FnPathByContext) -> Self {
Item {
item_kind: ItemKind::Link(label, path),
..Default::default()
}
}
pub fn link_blank(label: L10n, path: FnPathByContext) -> Self {
Item {
item_kind: ItemKind::LinkBlank(label, path),
..Default::default()
}
}
pub fn html(content: Html) -> Self {
Item {
item_kind: ItemKind::Html(Content::with(content)),
..Default::default()
}
}
pub fn submenu(label: L10n, submenu: menu::Submenu) -> Self {
Item {
item_kind: ItemKind::Submenu(label, SubmenuItems::with(submenu)),
..Default::default()
}
}
pub fn megamenu(label: L10n, megamenu: menu::Megamenu) -> Self {
Item {
item_kind: ItemKind::Megamenu(label, MegamenuGroups::with(megamenu)),
..Default::default()
}
}
// **< Item BUILDER >***************************************************************************
#[builder_fn]
pub fn with_description(mut self, text: L10n) -> Self {
self.description.alter_value(text);
self
}
#[builder_fn]
pub fn with_left_icon<I: Into<Icon>>(mut self, icon: Option<I>) -> Self {
self.left_icon.alter_component(icon.map(Into::into));
self
}
#[builder_fn]
pub fn with_right_icon<I: Into<Icon>>(mut self, icon: Option<I>) -> Self {
self.right_icon.alter_component(icon.map(Into::into));
self
}
// **< Item GETTERS >***************************************************************************
pub fn item_kind(&self) -> &ItemKind {
&self.item_kind
}
pub fn description(&self) -> &AttrL10n {
&self.description
}
pub fn left_icon(&self) -> &Typed<Icon> {
&self.left_icon
}
pub fn right_icon(&self) -> &Typed<Icon> {
&self.right_icon
}
}

View file

@ -1,57 +0,0 @@
use crate::prelude::*;
#[rustfmt::skip]
#[derive(AutoDefault)]
pub struct Megamenu {
id : AttrId,
groups: Children,
}
impl Component for Megamenu {
fn new() -> Self {
Megamenu::default()
}
fn id(&self) -> Option<String> {
self.id.get()
}
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
PrepareMarkup::With(html! {
div id=[self.id()] class="menu__mega" {
(self.groups().render(cx))
}
})
}
}
impl Megamenu {
// **< Megamenu BUILDER >***********************************************************************
/// Establece el identificador único (`id`) del megamenú.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self
}
/// Añade un nuevo grupo al menú.
pub fn add_group(mut self, group: menu::Group) -> Self {
self.groups.alter_typed(TypedOp::Add(Typed::with(group)));
self
}
/// Modifica la lista de grupos (`children`) aplicando una operación [`TypedOp`].
#[builder_fn]
pub fn with_groups(mut self, op: TypedOp<menu::Group>) -> Self {
self.groups.alter_typed(op);
self
}
// **< Megamenu GETTERS >***********************************************************************
/// Devuelve la lista de grupos (`children`) del megamenú.
pub fn groups(&self) -> &Children {
&self.groups
}
}

View file

@ -1,108 +0,0 @@
use crate::prelude::*;
#[rustfmt::skip]
#[derive(AutoDefault)]
pub struct Menu {
id : AttrId,
classes: AttrClasses,
items : Children,
}
impl Component for Menu {
fn new() -> Self {
Menu::default()
}
fn id(&self) -> Option<String> {
self.id.get()
}
fn setup_before_prepare(&mut self, _cx: &mut Context) {
self.alter_classes(ClassesOp::Prepend, "menu");
}
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
// cx.set_param::<bool>(PARAM_BASE_INCLUDE_MENU_ASSETS, &true);
// cx.set_param::<bool>(PARAM_BASE_INCLUDE_ICONS, &true);
PrepareMarkup::With(html! {
div id=[self.id()] class=[self.classes().get()] {
div class="menu__wrapper" {
div class="menu__panel" {
div class="menu__overlay" {}
nav class="menu__nav" {
div class="menu__header" {
button type="button" class="menu__back" {
(Icon::svg(html! {
path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0" {}
}).render(cx))
}
div class="menu__title" {}
button type="button" class="menu__close" {
(Icon::svg(html! {
path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z" {}
}).render(cx))
}
}
ul class="menu__list" {
(self.items().render(cx))
}
}
}
button
type="button"
class="menu__trigger"
title=[L10n::l("menu_toggle").lookup(cx)]
{
(Icon::svg(html! {
path fill-rule="evenodd" d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5" {}
}).render(cx))
}
}
}
})
}
}
impl Menu {
// **< Menu BUILDER >***************************************************************************
/// Establece el identificador único (`id`) del menú.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self
}
/// Modifica la lista de clases CSS aplicadas al menú.
#[builder_fn]
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.classes.alter_value(op, classes);
self
}
/// Añade un nuevo ítem al menú.
pub fn add_item(mut self, item: menu::Item) -> Self {
self.items.alter_typed(TypedOp::Add(Typed::with(item)));
self
}
/// Modifica la lista de ítems (`children`) aplicando una operación [`TypedOp`].
#[builder_fn]
pub fn with_items(mut self, op: TypedOp<menu::Item>) -> Self {
self.items.alter_typed(op);
self
}
// **< Menu GETTERS >***************************************************************************
/// Devuelve las clases CSS asociadas al menú.
pub fn classes(&self) -> &AttrClasses {
&self.classes
}
/// Devuelve la lista de ítems (`children`) del menú.
pub fn items(&self) -> &Children {
&self.items
}
}

View file

@ -1,73 +0,0 @@
use crate::prelude::*;
#[rustfmt::skip]
#[derive(AutoDefault)]
pub struct Submenu {
id : AttrId,
title: AttrL10n,
items: Children,
}
impl Component for Submenu {
fn new() -> Self {
Submenu::default()
}
fn id(&self) -> Option<String> {
self.id.get()
}
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
PrepareMarkup::With(html! {
div id=[self.id()] class="menu__submenu" {
@if let Some(title) = self.title().lookup(cx) {
h4 class="menu__submenu-title" { (title) }
}
ul {
(self.items().render(cx))
}
}
})
}
}
impl Submenu {
// **< Submenu BUILDER >************************************************************************
/// Establece el identificador único (`id`) del submenú.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self
}
#[builder_fn]
pub fn with_title(mut self, title: L10n) -> Self {
self.title.alter_value(title);
self
}
/// Añade un nuevo ítem al submenú.
pub fn add_item(mut self, item: menu::Item) -> Self {
self.items.alter_typed(TypedOp::Add(Typed::with(item)));
self
}
/// Modifica la lista de ítems (`children`) aplicando una operación [`TypedOp`].
#[builder_fn]
pub fn with_items(mut self, op: TypedOp<menu::Item>) -> Self {
self.items.alter_typed(op);
self
}
// **< Submenu GETTERS >************************************************************************
pub fn title(&self) -> &AttrL10n {
&self.title
}
/// Devuelve la lista de ítems (`children`) del submenú.
pub fn items(&self) -> &Children {
&self.items
}
}