🎉 [megamenu] Nuevo componente para PageTop

This commit is contained in:
Manuel Cillero 2023-02-03 22:25:34 +01:00
parent 8ec2c698c8
commit b02c729864
19 changed files with 184 additions and 105 deletions

View file

@ -6,6 +6,7 @@ members = [
"pagetop-macros", "pagetop-macros",
"pagetop-build", "pagetop-build",
"pagetop-jquery", "pagetop-jquery",
"pagetop-megamenu",
# Modules. # Modules.
"pagetop-admin", "pagetop-admin",
"pagetop-user", "pagetop-user",

View file

@ -15,4 +15,6 @@ license = "Apache-2.0 OR MIT"
[dependencies] [dependencies]
pagetop = { path = "../pagetop", version = "0.0" } pagetop = { path = "../pagetop", version = "0.0" }
pagetop-megamenu = { path = "../pagetop-megamenu", version = "0.0" }
maud = "0.24.0" maud = "0.24.0"

View file

@ -21,15 +21,19 @@ impl ModuleTrait for Admin {
Some(l("module_description")) Some(l("module_description"))
} }
fn configure_service(&self, cfg: &mut server::web::ServiceConfig) { fn dependencies(&self) -> Vec<ModuleStaticRef> {
cfg.service( vec![&pagetop_megamenu::MegaMenu]
server::web::scope("/admin").route("", server::web::get().to(summary::summary)),
);
} }
fn actions(&self) -> Vec<HookAction> { fn actions(&self) -> Vec<HookAction> {
vec![hook_action!(BeforeRenderPageHook => before_render_page)] vec![hook_action!(BeforeRenderPageHook => before_render_page)]
} }
fn configure_service(&self, cfg: &mut server::web::ServiceConfig) {
cfg.service(
server::web::scope("/admin").route("", server::web::get().to(summary::summary)),
);
}
} }
fn before_render_page(page: &mut Page) { fn before_render_page(page: &mut Page) {

View file

@ -1,51 +1,50 @@
//use super::l; use super::l;
use pagetop::prelude::*; use pagetop::prelude::*;
use pagetop_megamenu::component::{MegaMenu, MegaMenuItem};
pub async fn summary(request: server::HttpRequest) -> ResultPage<Markup, FatalError> { pub async fn summary(request: server::HttpRequest) -> ResultPage<Markup, FatalError> {
/* let top_menu = MegaMenu::new()
let top_menu = Menu::new() .with_item(MegaMenuItem::label(l("module_name").as_str()))
.with_item(MenuItem::label(l("module_name").as_str())) .with_item(MegaMenuItem::link("Opción 2", "https://www.google.es"))
.with_item(MenuItem::link("Opción 2", "https://www.google.es")) .with_item(MegaMenuItem::link_blank("Opción 3", "https://www.google.es"))
.with_item(MenuItem::link_blank("Opción 3", "https://www.google.es")) .with_item(MegaMenuItem::submenu(
.with_item(MenuItem::submenu(
"Submenú 1", "Submenú 1",
Menu::new() MegaMenu::new()
.with_item(MenuItem::label("Opción 1")) .with_item(MegaMenuItem::label("Opción 1"))
.with_item(MenuItem::label("Opción 2")), .with_item(MegaMenuItem::label("Opción 2")),
)) ))
.with_item(MenuItem::separator()) .with_item(MegaMenuItem::separator())
.with_item(MenuItem::submenu( .with_item(MegaMenuItem::submenu(
"Submenú 2", "Submenú 2",
Menu::new() MegaMenu::new()
.with_item(MenuItem::label("Opción 1")) .with_item(MegaMenuItem::label("Opción 1"))
.with_item(MenuItem::label("Opción 2")), .with_item(MegaMenuItem::label("Opción 2")),
)) ))
.with_item(MenuItem::label("Opción 4")); .with_item(MegaMenuItem::label("Opción 4"));
let side_menu = Menu::new() let side_menu = MegaMenu::new()
.with_item(MenuItem::label("Opción 1")) .with_item(MegaMenuItem::label("Opción 1"))
.with_item(MenuItem::link("Opción 2", "https://www.google.es")) .with_item(MegaMenuItem::link("Opción 2", "https://www.google.es"))
.with_item(MenuItem::link_blank("Opción 3", "https://www.google.es")) .with_item(MegaMenuItem::link_blank("Opción 3", "https://www.google.es"))
.with_item(MenuItem::submenu( .with_item(MegaMenuItem::submenu(
"Submenú 1", "Submenú 1",
Menu::new() MegaMenu::new()
.with_item(MenuItem::label("Opción 1")) .with_item(MegaMenuItem::label("Opción 1"))
.with_item(MenuItem::label("Opción 2")), .with_item(MegaMenuItem::label("Opción 2")),
)) ))
.with_item(MenuItem::separator()) .with_item(MegaMenuItem::separator())
.with_item(MenuItem::submenu( .with_item(MegaMenuItem::submenu(
"Submenú 2", "Submenú 2",
Menu::new() MegaMenu::new()
.with_item(MenuItem::label("Opción 1")) .with_item(MegaMenuItem::label("Opción 1"))
.with_item(MenuItem::label("Opción 2")), .with_item(MegaMenuItem::label("Opción 2")),
)) ))
.with_item(MenuItem::label("Opción 4")); .with_item(MegaMenuItem::label("Opción 4"));
*/
Page::new(request) Page::new(request)
.with_context(ContextOp::Theme("Bootsier")) .with_context(ContextOp::Theme("Bootsier"))
.with_title("Admin") .with_title("Admin")
/* .with_this_in("top-menu", top_menu) .with_this_in("top-menu", top_menu)
.with_this_in( .with_this_in(
"region-content", "region-content",
grid::Row::new() grid::Row::new()
@ -54,7 +53,6 @@ pub async fn summary(request: server::HttpRequest) -> ResultPage<Markup, FatalEr
p { "Columna 2"} p { "Columna 2"}
}))), }))),
) )
*/
.with_template("admin") .with_template("admin")
.render() .render()
} }

View file

@ -0,0 +1,23 @@
[package]
name = "pagetop-megamenu"
version = "0.0.1"
edition = "2021"
authors = [
"Manuel Cillero <manuel@cillero.es>"
]
description = """\
Component MegaMenu for PageTop applications.\
"""
homepage = "https://pagetop.cillero.es"
repository = "https://github.com/manuelcillero/pagetop"
license = "Apache-2.0 OR MIT"
[dependencies]
pagetop = { path = "../pagetop", version = "0.0" }
pagetop-jquery = { path = "../pagetop-jquery", version = "0.0" }
static-files = "0.2.3"
maud = "0.24.0"
[build-dependencies]
pagetop-build = { path = "../pagetop-build", version = "0.0" }

View file

@ -0,0 +1,26 @@
Componente MegaMenu para aplicaciones desarrolladas con **PageTop**.
[PageTop](https://github.com/manuelcillero/pagetop/tree/main/pagetop), es un entorno de desarrollo
basado en algunos de los *crates* más estables y populares del ecosistema Rust para proporcionar
APIs, patrones de desarrollo y buenas prácticas para la creación de soluciones web SSR (*Server-Side
Rendering*).
# 🚧 Advertencia
**PageTop** sólo libera actualmente versiones de desarrollo. La API no es estable y los cambios son
constantes. No puede considerarse preparado hasta que se libere la versión **0.1.0**.
# 📜 Licencia
Este proyecto tiene licencia, de hecho tiene dos, puedes aplicar cualquiera de las siguientes a tu
elección:
* Licencia Apache versión 2.0
([LICENSE-APACHE](https://github.com/manuelcillero/pagetop/blob/main/LICENSE-APACHE) o
[http://www.apache.org/licenses/LICENSE-2.0]).
* Licencia MIT
([LICENSE-MIT](https://github.com/manuelcillero/pagetop/blob/main/LICENSE-MIT) o
[http://opensource.org/licenses/MIT]).

View file

@ -0,0 +1,3 @@
fn main() -> std::io::Result<()> {
pagetop_build::bundle_resources("./static", "mengamenu", None)
}

View file

@ -1,36 +1,36 @@
use crate::prelude::*; use pagetop::prelude::*;
pub_handle!(COMPONENT_MENUITEM); pub_handle!(COMPONENT_MEGAMENUITEM);
#[derive(Default)] #[derive(Default)]
pub enum MenuItemType { pub enum MegaMenuItemType {
#[default] #[default]
Void, Void,
Label(String), Label(String),
Link(String, String), Link(String, String),
LinkBlank(String, String), LinkBlank(String, String),
Html(Markup), Html(Markup),
Submenu(String, Menu), Submenu(String, MegaMenu),
Separator, Separator,
} }
// MenuItem. // MegaMenuItem.
#[rustfmt::skip] #[rustfmt::skip]
#[derive(Default)] #[derive(Default)]
pub struct MenuItem { pub struct MegaMenuItem {
weight : isize, weight : isize,
renderable: Renderable, renderable: Renderable,
item_type : MenuItemType, item_type : MegaMenuItemType,
} }
impl ComponentTrait for MenuItem { impl ComponentTrait for MegaMenuItem {
fn new() -> Self { fn new() -> Self {
MenuItem::default() MegaMenuItem::default()
} }
fn handle(&self) -> Handle { fn handle(&self) -> Handle {
COMPONENT_MENUITEM COMPONENT_MEGAMENUITEM
} }
fn weight(&self) -> isize { fn weight(&self) -> isize {
@ -43,23 +43,23 @@ impl ComponentTrait for MenuItem {
fn default_render(&self, rcx: &mut RenderContext) -> Markup { fn default_render(&self, rcx: &mut RenderContext) -> Markup {
match self.item_type() { match self.item_type() {
MenuItemType::Void => html! {}, MegaMenuItemType::Void => html! {},
MenuItemType::Label(label) => html! { MegaMenuItemType::Label(label) => html! {
li class="label" { a href="#" { (label) } } li class="label" { a href="#" { (label) } }
}, },
MenuItemType::Link(label, path) => html! { MegaMenuItemType::Link(label, path) => html! {
li class="link" { a href=(path) { (label) } } li class="link" { a href=(path) { (label) } }
}, },
MenuItemType::LinkBlank(label, path) => html! { MegaMenuItemType::LinkBlank(label, path) => html! {
li class="link_blank" { li class="link_blank" {
a href=(path) target="_blank" { (label) } a href=(path) target="_blank" { (label) }
} }
}, },
MenuItemType::Html(html) => html! { MegaMenuItemType::Html(html) => html! {
li class="html" { (*html) } li class="html" { (*html) }
}, },
MenuItemType::Submenu(label, menu) => html! { MegaMenuItemType::Submenu(label, menu) => html! {
li class="submenu" { li class="submenu" {
a href="#" { (label) } a href="#" { (label) }
ul { ul {
@ -67,7 +67,7 @@ impl ComponentTrait for MenuItem {
} }
} }
}, },
MenuItemType::Separator => html! { MegaMenuItemType::Separator => html! {
li class="separator" { } li class="separator" { }
}, },
} }
@ -82,50 +82,50 @@ impl ComponentTrait for MenuItem {
} }
} }
impl MenuItem { impl MegaMenuItem {
pub fn label(label: &str) -> Self { pub fn label(label: &str) -> Self {
MenuItem { MegaMenuItem {
item_type: MenuItemType::Label(label.to_owned()), item_type: MegaMenuItemType::Label(label.to_owned()),
..Default::default() ..Default::default()
} }
} }
pub fn link(label: &str, path: &str) -> Self { pub fn link(label: &str, path: &str) -> Self {
MenuItem { MegaMenuItem {
item_type: MenuItemType::Link(label.to_owned(), path.to_owned()), item_type: MegaMenuItemType::Link(label.to_owned(), path.to_owned()),
..Default::default() ..Default::default()
} }
} }
pub fn link_blank(label: &str, path: &str) -> Self { pub fn link_blank(label: &str, path: &str) -> Self {
MenuItem { MegaMenuItem {
item_type: MenuItemType::LinkBlank(label.to_owned(), path.to_owned()), item_type: MegaMenuItemType::LinkBlank(label.to_owned(), path.to_owned()),
..Default::default() ..Default::default()
} }
} }
pub fn html(html: Markup) -> Self { pub fn html(html: Markup) -> Self {
MenuItem { MegaMenuItem {
item_type: MenuItemType::Html(html), item_type: MegaMenuItemType::Html(html),
..Default::default() ..Default::default()
} }
} }
pub fn submenu(label: &str, menu: Menu) -> Self { pub fn submenu(label: &str, menu: MegaMenu) -> Self {
MenuItem { MegaMenuItem {
item_type: MenuItemType::Submenu(label.to_owned(), menu), item_type: MegaMenuItemType::Submenu(label.to_owned(), menu),
..Default::default() ..Default::default()
} }
} }
pub fn separator() -> Self { pub fn separator() -> Self {
MenuItem { MegaMenuItem {
item_type: MenuItemType::Separator, item_type: MegaMenuItemType::Separator,
..Default::default() ..Default::default()
} }
} }
// MenuItem BUILDER. // MegaMenuItem BUILDER.
#[fn_builder] #[fn_builder]
pub fn alter_weight(&mut self, weight: isize) -> &mut Self { pub fn alter_weight(&mut self, weight: isize) -> &mut Self {
@ -139,22 +139,22 @@ impl MenuItem {
self self
} }
// MenuItem GETTERS. // MegaMenuItem GETTERS.
pub fn item_type(&self) -> &MenuItemType { pub fn item_type(&self) -> &MegaMenuItemType {
&self.item_type &self.item_type
} }
} }
// Menu. // MegaMenu.
pub_handle!(COMPONENT_MENU); pub_handle!(COMPONENT_MEGAMENU);
hook_before_render_component!(HOOK_BEFORE_RENDER_MENU, Menu); hook_before_render_component!(HOOK_BEFORE_RENDER_MENU, MegaMenu);
#[rustfmt::skip] #[rustfmt::skip]
#[derive(Default)] #[derive(Default)]
pub struct Menu { pub struct MegaMenu {
weight : isize, weight : isize,
renderable: Renderable, renderable: Renderable,
id : IdentifierValue, id : IdentifierValue,
@ -163,13 +163,13 @@ pub struct Menu {
template : String, template : String,
} }
impl ComponentTrait for Menu { impl ComponentTrait for MegaMenu {
fn new() -> Self { fn new() -> Self {
Menu::default().with_classes(ClassesOp::SetDefault, "sm sm-clean") MegaMenu::default().with_classes(ClassesOp::SetDefault, "sm sm-clean")
} }
fn handle(&self) -> Handle { fn handle(&self) -> Handle {
COMPONENT_MENU COMPONENT_MEGAMENU
} }
fn weight(&self) -> isize { fn weight(&self) -> isize {
@ -186,17 +186,17 @@ impl ComponentTrait for Menu {
fn default_render(&self, rcx: &mut RenderContext) -> Markup { fn default_render(&self, rcx: &mut RenderContext) -> Markup {
rcx.alter(ContextOp::AddStyleSheet( rcx.alter(ContextOp::AddStyleSheet(
StyleSheet::located("/theme/menu/css/menu.css").with_version("1.1.1"), StyleSheet::located("/megamenu/css/menu.css").with_version("1.1.1"),
)) ))
.alter(ContextOp::AddStyleSheet( .alter(ContextOp::AddStyleSheet(
StyleSheet::located("/theme/menu/css/menu-clean.css").with_version("1.1.1"), StyleSheet::located("/megamenu/css/menu-clean.css").with_version("1.1.1"),
)) ))
.alter(ContextOp::AddJavaScript( .alter(ContextOp::AddJavaScript(
JavaScript::located("/theme/menu/js/menu.min.js").with_version("1.1.1"), JavaScript::located("/megamenu/js/menu.min.js").with_version("1.1.1"),
)) ));
.alter(ContextOp::AddJQuery); pagetop_jquery::JQuery::add_jquery(rcx);
let id = rcx.required_id::<Menu>(self.id()); let id = rcx.required_id::<MegaMenu>(self.id());
html! { html! {
ul id=(id) class=[self.classes().get()] { ul id=(id) class=[self.classes().get()] {
@ -220,8 +220,8 @@ impl ComponentTrait for Menu {
} }
} }
impl Menu { impl MegaMenu {
// Menu BUILDER. // MegaMenu BUILDER.
#[fn_builder] #[fn_builder]
pub fn alter_weight(&mut self, weight: isize) -> &mut Self { pub fn alter_weight(&mut self, weight: isize) -> &mut Self {
@ -248,7 +248,7 @@ impl Menu {
} }
#[fn_builder] #[fn_builder]
pub fn alter_item(&mut self, item: MenuItem) -> &mut Self { pub fn alter_item(&mut self, item: MegaMenuItem) -> &mut Self {
self.items.add(item); self.items.add(item);
self self
} }
@ -259,7 +259,7 @@ impl Menu {
self self
} }
// Menu GETTERS. // MegaMenu GETTERS.
pub fn id(&self) -> &IdentifierValue { pub fn id(&self) -> &IdentifierValue {
&self.id &self.id

View file

@ -0,0 +1,23 @@
use pagetop::prelude::*;
pub mod component;
pub_handle!(MODULE_MEGAMENU);
include!(concat!(env!("OUT_DIR"), "/megamenu.rs"));
pub struct MegaMenu;
impl ModuleTrait for MegaMenu {
fn handle(&self) -> Handle {
MODULE_MEGAMENU
}
fn dependencies(&self) -> Vec<ModuleStaticRef> {
vec![&pagetop_jquery::JQuery]
}
fn configure_service(&self, cfg: &mut server::web::ServiceConfig) {
serve_static_files!(cfg, "/megamenu", bundle_megamenu);
}
}

View file

@ -17,8 +17,6 @@ mod block;
pub use block::{Block, COMPONENT_BLOCK}; pub use block::{Block, COMPONENT_BLOCK};
mod image; mod image;
pub use image::{Image, COMPONENT_IMAGE}; pub use image::{Image, COMPONENT_IMAGE};
//mod menu;
//pub use menu::{Menu, MenuItem, MenuItemType, COMPONENT_MENU, COMPONENT_MENUITEM};
pub mod form_element; pub mod form_element;
pub use form_element::{Form, FormMethod, COMPONENT_FORM}; pub use form_element::{Form, FormMethod, COMPONENT_FORM};

View file

@ -75,7 +75,7 @@ pub fn component_mut<C: 'static>(component: &mut dyn ComponentTrait) -> &mut C {
#[macro_export] #[macro_export]
macro_rules! hook_before_render_component { macro_rules! hook_before_render_component {
( $ACTION_HANDLE:ident, $Component:ty ) => { ( $ACTION_HANDLE:ident, $Component:ty ) => {
paste::paste! { $crate::paste! {
$crate::pub_handle!($ACTION_HANDLE); $crate::pub_handle!($ACTION_HANDLE);
type Action = fn(&$Component, &mut RenderContext); type Action = fn(&$Component, &mut RenderContext);
@ -127,7 +127,7 @@ macro_rules! hook_before_render_component {
} }
#[inline(always)] #[inline(always)]
fn before_render_inline(component: &mut $Component, rcx: &mut RenderContext) { pub fn before_render_inline(component: &mut $Component, rcx: &mut RenderContext) {
run_actions($ACTION_HANDLE, |action| run_actions($ACTION_HANDLE, |action|
action_ref::<[< BeforeRender $Component >]>(&**action) action_ref::<[< BeforeRender $Component >]>(&**action)
.run(component, rcx) .run(component, rcx)

View file

@ -42,6 +42,7 @@
pub use concat_string::concat_string; pub use concat_string::concat_string;
pub use doc_comment::doc_comment; pub use doc_comment::doc_comment;
pub use once_cell::sync::Lazy as LazyStatic; pub use once_cell::sync::Lazy as LazyStatic;
pub use paste::paste;
pub use tracing_unwrap::ResultExt; pub use tracing_unwrap::ResultExt;
pub use pagetop_macros::fn_builder; pub use pagetop_macros::fn_builder;

View file

@ -2,7 +2,7 @@
pub use crate::{concat_string, fn_builder, LazyStatic, ResultExt}; pub use crate::{concat_string, fn_builder, LazyStatic, ResultExt};
// Macros. // Macros.
pub use crate::{args, pub_config, pub_handle, pub_locale, serve_static_files}; pub use crate::{args, paste, pub_config, pub_handle, pub_locale, serve_static_files};
// Helpers. // Helpers.
pub use crate::util; pub use crate::util;