diff --git a/pagetop/src/base/component/anchor.rs b/pagetop/src/base/component/anchor.rs new file mode 100644 index 00000000..d0534694 --- /dev/null +++ b/pagetop/src/base/component/anchor.rs @@ -0,0 +1,227 @@ +use crate::prelude::*; + +pub const ANCHOR_COMPONENT: &str = "pagetop::component::anchor"; + +pub enum AnchorType { + Button, + Link, + Location, +} + +pub enum AnchorTarget { + Blank, + Context(String), + Default, + Parent, + Top, +} + +pub struct Anchor { + renderable : fn() -> bool, + weight : isize, + anchor_type: AnchorType, + href : OptAttr, + html : Markup, + target : AnchorTarget, + id : OptIden, + classes : Classes, + template : String, +} + +impl ComponentTrait for Anchor { + fn new() -> Self { + Anchor { + renderable : render_always, + weight : 0, + anchor_type: AnchorType::Link, + href : OptAttr::new(), + html : html! {}, + target : AnchorTarget::Default, + id : OptIden::new(), + classes : Classes::new(), + template : "default".to_owned(), + } + } + + fn handler(&self) -> &'static str { + ANCHOR_COMPONENT + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> isize { + self.weight + } + + fn default_render(&self, _: &mut Assets) -> Markup { + let target = match &self.target() { + AnchorTarget::Blank => Some("_blank"), + AnchorTarget::Context(name) => Some(name.as_str()), + AnchorTarget::Parent => Some("_parent"), + AnchorTarget::Top => Some("_top"), + _ => None, + }; + html! { + a + id=[self.id()] + class=[self.classes()] + href=[self.href()] + target=[target] + { + (*self.html()) + } + } + } + + fn as_ref_any(&self) -> &dyn AnyComponent { + self + } + + fn as_mut_any(&mut self) -> &mut dyn AnyComponent { + self + } +} + +impl Anchor { + pub fn link(href: &str, html: Markup) -> Self { + Anchor::new().with_href(href).with_html(html) + } + + pub fn button(href: &str, html: Markup) -> Self { + Anchor::new().with_type(AnchorType::Button).with_href(href).with_html(html) + } + + pub fn location(id: &str) -> Self { + Anchor::new().with_type(AnchorType::Location).with_id(id) + } + + // Anchor BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.alter_renderable(renderable); + self + } + + pub fn with_weight(mut self, weight: isize) -> Self { + self.alter_weight(weight); + self + } + + pub fn with_type(mut self, anchor_type: AnchorType) -> Self { + self.alter_type(anchor_type); + self + } + + pub fn with_href(mut self, href: &str) -> Self { + self.alter_href(href); + self + } + + pub fn with_html(mut self, html: Markup) -> Self { + self.alter_html(html); + self + } + + pub fn with_target(mut self, target: AnchorTarget) -> Self { + self.alter_target(target); + self + } + + pub fn with_id(mut self, id: &str) -> Self { + self.alter_id(id); + self + } + + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Anchor ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: isize) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_type(&mut self, anchor_type: AnchorType) -> &mut Self { + self.anchor_type = anchor_type; + self.classes.alter(match self.anchor_type { + AnchorType::Button => "btn btn-primary", + _ => "", + }, ClassesOp::SetDefault); + self + } + + pub fn alter_href(&mut self, href: &str) -> &mut Self { + self.href.with_value(href); + self + } + + pub fn alter_html(&mut self, html: Markup) -> &mut Self { + self.html = html; + self + } + + pub fn alter_target(&mut self, target: AnchorTarget) -> &mut Self { + self.target = target; + self + } + + pub fn alter_id(&mut self, id: &str) -> &mut Self { + self.id.with_value(id); + self + } + + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); + self + } + + pub fn alter_template(&mut self, template: &str) -> &mut Self { + self.template = template.to_owned(); + self + } + + // Anchor GETTERS. + + pub fn anchor_type(&self) -> &AnchorType { + &self.anchor_type + } + + pub fn href(&self) -> &Option { + self.href.option() + } + + pub fn html(&self) -> &Markup { + &self.html + } + + pub fn target(&self) -> &AnchorTarget { + &self.target + } + + pub fn id(&self) -> &Option { + self.id.option() + } + + pub fn classes(&self) -> &Option { + self.classes.option() + } + + pub fn template(&self) -> &str { + self.template.as_str() + } +} diff --git a/pagetop/src/base/component/heading.rs b/pagetop/src/base/component/heading.rs index 5023e611..fa17ca7e 100644 --- a/pagetop/src/base/component/heading.rs +++ b/pagetop/src/base/component/heading.rs @@ -2,28 +2,22 @@ use crate::prelude::*; pub const HEADING_COMPONENT: &str = "pagetop::component::heading"; -pub enum HeadingType { - H1(String), - H2(String), - H3(String), - H4(String), - H5(String), - H6(String), -} +pub enum HeadingType { H1, H2, H3, H4, H5, H6 } pub enum HeadingDisplay { XxLarge, Large, - Normal, Medium, Small, XxSmall, + Normal, } pub struct Heading { renderable: fn() -> bool, weight : isize, heading : HeadingType, + html : Markup, display : HeadingDisplay, id : OptIden, classes : Classes, @@ -35,7 +29,8 @@ impl ComponentTrait for Heading { Heading { renderable: render_always, weight : 0, - heading : HeadingType::H1("".to_owned()), + heading : HeadingType::H1, + html : html! {}, display : HeadingDisplay::Normal, id : OptIden::new(), classes : Classes::new(), @@ -57,12 +52,12 @@ impl ComponentTrait for Heading { fn default_render(&self, _: &mut Assets) -> Markup { html! { @match &self.heading() { - HeadingType::H1(text) => h1 id=[self.id()] class=[self.classes()] { (text) }, - HeadingType::H2(text) => h2 id=[self.id()] class=[self.classes()] { (text) }, - HeadingType::H3(text) => h3 id=[self.id()] class=[self.classes()] { (text) }, - HeadingType::H4(text) => h4 id=[self.id()] class=[self.classes()] { (text) }, - HeadingType::H5(text) => h5 id=[self.id()] class=[self.classes()] { (text) }, - HeadingType::H6(text) => h6 id=[self.id()] class=[self.classes()] { (text) }, + HeadingType::H1 => h1 id=[self.id()] class=[self.classes()] { (*self.html()) }, + HeadingType::H2 => h2 id=[self.id()] class=[self.classes()] { (*self.html()) }, + HeadingType::H3 => h3 id=[self.id()] class=[self.classes()] { (*self.html()) }, + HeadingType::H4 => h4 id=[self.id()] class=[self.classes()] { (*self.html()) }, + HeadingType::H5 => h5 id=[self.id()] class=[self.classes()] { (*self.html()) }, + HeadingType::H6 => h6 id=[self.id()] class=[self.classes()] { (*self.html()) }, }} } @@ -76,8 +71,28 @@ impl ComponentTrait for Heading { } impl Heading { - pub fn with(heading: HeadingType) -> Self { - Heading::new().with_heading(heading) + pub fn h1(html: Markup) -> Self { + Heading::new().with_heading(HeadingType::H1).with_html(html) + } + + pub fn h2(html: Markup) -> Self { + Heading::new().with_heading(HeadingType::H2).with_html(html) + } + + pub fn h3(html: Markup) -> Self { + Heading::new().with_heading(HeadingType::H3).with_html(html) + } + + pub fn h4(html: Markup) -> Self { + Heading::new().with_heading(HeadingType::H4).with_html(html) + } + + pub fn h5(html: Markup) -> Self { + Heading::new().with_heading(HeadingType::H5).with_html(html) + } + + pub fn h6(html: Markup) -> Self { + Heading::new().with_heading(HeadingType::H6).with_html(html) } // Heading BUILDER. @@ -97,6 +112,11 @@ impl Heading { self } + pub fn with_html(mut self, html: Markup) -> Self { + self.alter_html(html); + self + } + pub fn with_display(mut self, display: HeadingDisplay) -> Self { self.alter_display(display); self @@ -134,15 +154,20 @@ impl Heading { self } + pub fn alter_html(&mut self, html: Markup) -> &mut Self { + self.html = html; + self + } + pub fn alter_display(&mut self, display: HeadingDisplay) -> &mut Self { self.display = display; self.classes.alter(match &self.display() { - HeadingDisplay::XxLarge => "display-2", - HeadingDisplay::Large => "display-3", - HeadingDisplay::Normal => "", - HeadingDisplay::Medium => "display-4", - HeadingDisplay::Small => "display-5", - HeadingDisplay::XxSmall => "display-6", + HeadingDisplay::XxLarge => "display-2", + HeadingDisplay::Large => "display-3", + HeadingDisplay::Medium => "display-4", + HeadingDisplay::Small => "display-5", + HeadingDisplay::XxSmall => "display-6", + HeadingDisplay::Normal => "", }, ClassesOp::SetDefault); self } @@ -168,6 +193,10 @@ impl Heading { &self.heading } + pub fn html(&self) -> &Markup { + &self.html + } + pub fn display(&self) -> &HeadingDisplay { &self.display } diff --git a/pagetop/src/base/component/mod.rs b/pagetop/src/base/component/mod.rs index 986ba6f5..22caca38 100644 --- a/pagetop/src/base/component/mod.rs +++ b/pagetop/src/base/component/mod.rs @@ -17,6 +17,10 @@ mod paragraph; pub use paragraph::{ PARAGRAPH_COMPONENT, Paragraph, ParagraphDisplay }; +mod anchor; +pub use anchor::{ + ANCHOR_COMPONENT, Anchor, AnchorTarget, AnchorType +}; mod block; pub use block::{ BLOCK_COMPONENT, Block diff --git a/pagetop/src/base/component/paragraph.rs b/pagetop/src/base/component/paragraph.rs index 1cf7c01b..025d9565 100644 --- a/pagetop/src/base/component/paragraph.rs +++ b/pagetop/src/base/component/paragraph.rs @@ -5,11 +5,10 @@ pub const PARAGRAPH_COMPONENT: &str = "pagetop::component::paragraph"; pub enum ParagraphDisplay { XxLarge, Large, - MediumPlus, - Normal, Medium, Small, XxSmall, + Normal, } pub struct Paragraph { @@ -123,18 +122,14 @@ impl Paragraph { pub fn alter_display(&mut self, display: ParagraphDisplay) -> &mut Self { self.display = display; - self.classes.alter( - match &self.display() { - ParagraphDisplay::XxLarge => "fs-1", - ParagraphDisplay::Large => "fs-2", - ParagraphDisplay::MediumPlus => "fs-3", - ParagraphDisplay::Normal => "", - ParagraphDisplay::Medium => "fs-4", - ParagraphDisplay::Small => "fs-5", - ParagraphDisplay::XxSmall => "fs-6", - }, - ClassesOp::SetDefault - ); + self.classes.alter(match &self.display() { + ParagraphDisplay::XxLarge => "fs-2", + ParagraphDisplay::Large => "fs-3", + ParagraphDisplay::Medium => "fs-4", + ParagraphDisplay::Small => "fs-5", + ParagraphDisplay::XxSmall => "fs-6", + ParagraphDisplay::Normal => "", + }, ClassesOp::SetDefault); self } diff --git a/pagetop/src/base/module/demopage/mod.rs b/pagetop/src/base/module/demopage/mod.rs index 41c398c0..f8753638 100644 --- a/pagetop/src/base/module/demopage/mod.rs +++ b/pagetop/src/base/module/demopage/mod.rs @@ -40,30 +40,27 @@ fn hello_world() -> Container { Container::header() .add(grid::Row::new() .add_column(grid::Column::new() - .add(Chunck::with(html! { - div class="area-title" { - (t("welcome_to", &args![ - "app" => SETTINGS.app.name.as_str() - ])) - } + .add(Heading::h1(html! { + (l("page_title")) + }).with_display(HeadingDisplay::Large)) + .add(Paragraph::with(html! { + (t("welcome_to", &args![ + "app" => SETTINGS.app.name.as_str() + ])) })) - .add(Heading::with(HeadingType::H1( - l("page_title")) - ).with_display(HeadingDisplay::Large)) .add(Paragraph::with(html! { (e("welcome_intro", &args![ - "app" => format!( - "{}", - &SETTINGS.app.name - ) + "app" => format!("{}", &SETTINGS.app.name) ])) - }).with_display(ParagraphDisplay::Large)) + }).with_display(ParagraphDisplay::Small)) + .add(Paragraph::with(html! { + (e("welcome_pagetop", &args![ + "pagetop" => "PageTop" + ])) + })) + .add(Anchor::button("#", html! { ("Offered services") })) + .add(Anchor::button("#", html! { ("Get quote") })) .add(Chunck::with(html! { - p { - (e("welcome_pagetop", &args![ - "pagetop" => "PageTop" - ])) - } a class="btn-solid-lg" href="#services" { "Offered services" } diff --git a/pagetop/src/base/theme/bulmix/mod.rs b/pagetop/src/base/theme/bulmix/mod.rs index 7bdb0890..b4a360fb 100644 --- a/pagetop/src/base/theme/bulmix/mod.rs +++ b/pagetop/src/base/theme/bulmix/mod.rs @@ -38,32 +38,32 @@ impl ThemeTrait for Bulmix { match component.handler() { HEADING_COMPONENT => { let h = component_mut::(component); - h.alter_classes( - concat_string!("title ", match h.display() { - HeadingDisplay::XxLarge => "is-1", - HeadingDisplay::Large => "is-2", - HeadingDisplay::Normal => "", - HeadingDisplay::Medium => "is-3", - HeadingDisplay::Small => "is-4", - HeadingDisplay::XxSmall => "is-5", - }).as_str(), - ClassesOp::SetDefault - ); + h.alter_classes(concat_string!("title ", match h.display() { + HeadingDisplay::XxLarge => "is-1", + HeadingDisplay::Large => "is-2", + HeadingDisplay::Medium => "is-3", + HeadingDisplay::Small => "is-4", + HeadingDisplay::XxSmall => "is-5", + HeadingDisplay::Normal => "", + }).as_str(), ClassesOp::SetDefault); }, PARAGRAPH_COMPONENT => { let p = component_mut::(component); - p.alter_classes( - match p.display() { - ParagraphDisplay::XxLarge => "is-size-2", - ParagraphDisplay::Large => "is-size-3", - ParagraphDisplay::MediumPlus => "is-size-4", - ParagraphDisplay::Normal => "", - ParagraphDisplay::Medium => "is-size-5", - ParagraphDisplay::Small => "is-size-6", - ParagraphDisplay::XxSmall => "is-size-7", - }, - ClassesOp::SetDefault - ); + p.alter_classes(match p.display() { + ParagraphDisplay::XxLarge => "is-size-2", + ParagraphDisplay::Large => "is-size-3", + ParagraphDisplay::Medium => "is-size-4", + ParagraphDisplay::Small => "is-size-5", + ParagraphDisplay::XxSmall => "is-size-6", + ParagraphDisplay::Normal => "", + }, ClassesOp::SetDefault); + }, + ANCHOR_COMPONENT => { + let a = component_mut::(component); + a.alter_classes(match a.anchor_type() { + AnchorType::Button => "button is-primary", + _ => "", + }, ClassesOp::SetDefault); }, grid::ROW_COMPONENT => { let row = component_mut::(component); @@ -71,7 +71,7 @@ impl ThemeTrait for Bulmix { }, grid::COLUMN_COMPONENT => { let col = component_mut::(component); - col.alter_classes("column", ClassesOp::SetDefault); + col.alter_classes("column content", ClassesOp::SetDefault); }, _ => {}, } diff --git a/pagetop/src/html/classes.rs b/pagetop/src/html/classes.rs index aa629aaf..0623baa2 100644 --- a/pagetop/src/html/classes.rs +++ b/pagetop/src/html/classes.rs @@ -8,6 +8,7 @@ pub enum ClassesOp { Replace(&'static str), Reset, SetDefault, + SetDefaultIfEmpty, } pub struct Classes { @@ -75,6 +76,10 @@ impl Classes { ClassesOp::Reset => self.added = classes.to_owned(), ClassesOp::SetDefault => self.default = classes.to_owned(), + + ClassesOp::SetDefaultIfEmpty => if self.default.is_empty() { + self.default = classes.to_owned() + }, } self.option = Some(concat_string!(self.default, " ", self.added).trim().to_owned()); self