Modifica estilos en línea sólo para composición

Se limitan los estilos que pueden añadirse en línea en los componentes a
sólo los que afectan a la composición. Inicialmente se aceptan márgenes
exteriores (margin) y espacios interiores (padding).
This commit is contained in:
Manuel Cillero 2022-07-04 01:21:53 +02:00
parent 37dbcaa84a
commit e2103f0943
27 changed files with 513 additions and 413 deletions

View file

@ -22,13 +22,14 @@ pub struct Anchor {
renderable : fn() -> bool, renderable : fn() -> bool,
weight : isize, weight : isize,
anchor_type: AnchorType, anchor_type: AnchorType,
href : OptAttr, href : AttributeValue,
html : Markup, html : Markup,
left_icon : AnchorIcon, left_icon : AnchorIcon,
right_icon : AnchorIcon, right_icon : AnchorIcon,
target : AnchorTarget, target : AnchorTarget,
id : OptIden, id : IdentifierValue,
classes : Classes, classes : Classes,
layout : Layout,
template : String, template : String,
} }
@ -38,13 +39,14 @@ impl ComponentTrait for Anchor {
renderable : render_always, renderable : render_always,
weight : 0, weight : 0,
anchor_type: AnchorType::Link, anchor_type: AnchorType::Link,
href : OptAttr::new(), href : AttributeValue::new(),
html : html! {}, html : html! {},
left_icon : AnchorIcon::new(), left_icon : AnchorIcon::new(),
right_icon : AnchorIcon::new(), right_icon : AnchorIcon::new(),
target : AnchorTarget::Default, target : AnchorTarget::Default,
id : OptIden::new(), id : IdentifierValue::new(),
classes : Classes::new(), classes : Classes::new(),
layout : Layout::new(),
template : "default".to_owned(), template : "default".to_owned(),
} }
} }
@ -71,9 +73,10 @@ impl ComponentTrait for Anchor {
}; };
html! { html! {
a a
id=[self.id()] id=[self.id().get()]
class=[self.classes()] class=[self.classes().get()]
href=[self.href()] style=[self.layout().get()]
href=[self.href().get()]
target=[target] target=[target]
{ {
(self.left_icon().render(context)) (self.left_icon().render(context))
@ -157,6 +160,11 @@ impl Anchor {
self self
} }
pub fn with_layout(mut self, property: LayoutProperty, value: LayoutUnit) -> Self {
self.alter_layout(property, value);
self
}
pub fn using_template(mut self, template: &str) -> Self { pub fn using_template(mut self, template: &str) -> Self {
self.alter_template(template); self.alter_template(template);
self self
@ -195,13 +203,13 @@ impl Anchor {
pub fn alter_left_icon(&mut self, icon: Icon) -> &mut Self { pub fn alter_left_icon(&mut self, icon: Icon) -> &mut Self {
self.left_icon.clear(); self.left_icon.clear();
self.left_icon.add(icon.with_inline_style("margin-right", Some("5px"))); self.left_icon.add(icon.with_layout(LayoutProperty::MarginRight, LayoutUnit::Px(5)));
self self
} }
pub fn alter_right_icon(&mut self, icon: Icon) -> &mut Self { pub fn alter_right_icon(&mut self, icon: Icon) -> &mut Self {
self.right_icon.clear(); self.right_icon.clear();
self.right_icon.add(icon.with_inline_style("margin-left", Some("5px"))); self.right_icon.add(icon.with_layout(LayoutProperty::MarginLeft, LayoutUnit::Px(5)));
self self
} }
@ -220,6 +228,11 @@ impl Anchor {
self self
} }
pub fn alter_layout(&mut self, property: LayoutProperty, value: LayoutUnit) -> &mut Self {
self.layout.add(property, value);
self
}
pub fn alter_template(&mut self, template: &str) -> &mut Self { pub fn alter_template(&mut self, template: &str) -> &mut Self {
self.template = template.to_owned(); self.template = template.to_owned();
self self
@ -231,8 +244,8 @@ impl Anchor {
&self.anchor_type &self.anchor_type
} }
pub fn href(&self) -> &Option<String> { pub fn href(&self) -> &AttributeValue {
self.href.option() &self.href
} }
pub fn html(&self) -> &Markup { pub fn html(&self) -> &Markup {
@ -251,12 +264,16 @@ impl Anchor {
&self.target &self.target
} }
pub fn id(&self) -> &Option<String> { pub fn id(&self) -> &IdentifierValue {
self.id.option() &self.id
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
}
pub fn layout(&self) -> &Layout {
&self.layout
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -6,8 +6,8 @@ pub struct Block {
renderable: fn() -> bool, renderable: fn() -> bool,
weight : isize, weight : isize,
components: ComponentsBundle, components: ComponentsBundle,
title : OptAttr, title : AttributeValue,
id : OptIden, id : IdentifierValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -18,8 +18,8 @@ impl ComponentTrait for Block {
renderable: render_always, renderable: render_always,
weight : 0, weight : 0,
components: ComponentsBundle::new(), components: ComponentsBundle::new(),
title : OptAttr::new(), title : AttributeValue::new(),
id : OptIden::new(), id : IdentifierValue::new(),
classes : Classes::new_with_default("block"), classes : Classes::new_with_default("block"),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -40,8 +40,8 @@ impl ComponentTrait for Block {
fn default_render(&self, context: &mut InContext) -> Markup { fn default_render(&self, context: &mut InContext) -> Markup {
let id = context.required_id::<Block>(self.id()); let id = context.required_id::<Block>(self.id());
html! { html! {
div id=(id) class=[self.classes()] { div id=(id) class=[self.classes().get()] {
@match self.title() { @match self.title().get() {
Some(title) => h2 class="block-title" { (title) }, Some(title) => h2 class="block-title" { (title) },
None => {} None => {}
} }
@ -140,16 +140,16 @@ impl Block {
// Block GETTERS. // Block GETTERS.
pub fn title(&self) -> &Option<String> { pub fn title(&self) -> &AttributeValue {
self.title.option() &self.title
} }
pub fn id(&self) -> &Option<String> { pub fn id(&self) -> &IdentifierValue {
self.id.option() &self.id
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -9,7 +9,7 @@ pub struct Container {
weight : isize, weight : isize,
components : ComponentsBundle, components : ComponentsBundle,
container : ContainerType, container : ContainerType,
id : OptIden, id : IdentifierValue,
classes : Classes, classes : Classes,
inner_classes: Classes, inner_classes: Classes,
template : String, template : String,
@ -22,7 +22,7 @@ impl ComponentTrait for Container {
weight : 0, weight : 0,
components : ComponentsBundle::new(), components : ComponentsBundle::new(),
container : ContainerType::Wrapper, container : ContainerType::Wrapper,
id : OptIden::new(), id : IdentifierValue::new(),
classes : Classes::new_with_default("container"), classes : Classes::new_with_default("container"),
inner_classes: Classes::new_with_default("container"), inner_classes: Classes::new_with_default("container"),
template : "default".to_owned(), template : "default".to_owned(),
@ -44,35 +44,35 @@ impl ComponentTrait for Container {
fn default_render(&self, context: &mut InContext) -> Markup { fn default_render(&self, context: &mut InContext) -> Markup {
match self.container_type() { match self.container_type() {
ContainerType::Header => html! { ContainerType::Header => html! {
header id=[self.id()] class=[self.classes()] { header id=[self.id().get()] class=[self.classes().get()] {
div class=[self.inner_classes()] { div class=[self.inner_classes().get()] {
(self.components().render(context)) (self.components().render(context))
} }
} }
}, },
ContainerType::Footer => html! { ContainerType::Footer => html! {
footer id=[self.id()] class=[self.classes()] { footer id=[self.id().get()] class=[self.classes().get()] {
div class=[self.inner_classes()] { div class=[self.inner_classes().get()] {
(self.components().render(context)) (self.components().render(context))
} }
} }
}, },
ContainerType::Main => html! { ContainerType::Main => html! {
main id=[self.id()] class=[self.classes()] { main id=[self.id().get()] class=[self.classes().get()] {
div class=[self.inner_classes()] { div class=[self.inner_classes().get()] {
(self.components().render(context)) (self.components().render(context))
} }
} }
}, },
ContainerType::Section => html! { ContainerType::Section => html! {
section id=[self.id()] class=[self.classes()] { section id=[self.id().get()] class=[self.classes().get()] {
div class=[self.inner_classes()] { div class=[self.inner_classes().get()] {
(self.components().render(context)) (self.components().render(context))
} }
} }
}, },
_ => html! { _ => html! {
div id=[self.id()] class=[self.classes()] { div id=[self.id().get()] class=[self.classes().get()] {
(self.components().render(context)) (self.components().render(context))
} }
} }
@ -194,16 +194,16 @@ impl Container {
&self.container &self.container
} }
pub fn id(&self) -> &Option<String> { pub fn id(&self) -> &IdentifierValue {
self.id.option() &self.id
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn inner_classes(&self) -> &Option<String> { pub fn inner_classes(&self) -> &Classes {
self.inner_classes.option() &self.inner_classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -8,10 +8,10 @@ pub struct Button {
renderable : fn() -> bool, renderable : fn() -> bool,
weight : isize, weight : isize,
button_type: ButtonType, button_type: ButtonType,
name : OptAttr, name : AttributeValue,
value : OptAttr, value : AttributeValue,
autofocus : OptAttr, autofocus : AttributeValue,
disabled : OptAttr, disabled : AttributeValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -22,10 +22,10 @@ impl ComponentTrait for Button {
renderable : render_always, renderable : render_always,
weight : 0, weight : 0,
button_type: ButtonType::Button, button_type: ButtonType::Button,
name : OptAttr::new(), name : AttributeValue::new(),
value : OptAttr::new(), value : AttributeValue::new(),
autofocus : OptAttr::new(), autofocus : AttributeValue::new(),
disabled : OptAttr::new(), disabled : AttributeValue::new(),
classes : Classes::new_with_default("btn btn-primary"), classes : Classes::new_with_default("btn btn-primary"),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -50,7 +50,7 @@ impl ComponentTrait for Button {
ButtonType::Reset => "reset", ButtonType::Reset => "reset",
ButtonType::Submit => "submit", ButtonType::Submit => "submit",
}; };
let id = match self.name() { let id = match self.name().get() {
Some(name) => Some(concat_string!("edit-", name)), Some(name) => Some(concat_string!("edit-", name)),
_ => None _ => None
}; };
@ -58,13 +58,13 @@ impl ComponentTrait for Button {
button button
type=(button_type) type=(button_type)
id=[id] id=[id]
class=[self.classes()] class=[self.classes().get()]
name=[self.name()] name=[self.name().get()]
value=[self.value()] value=[self.value().get()]
autofocus=[self.autofocus()] autofocus=[self.autofocus().get()]
disabled=[self.disabled()] disabled=[self.disabled().get()]
{ {
@match self.value() { @match self.value().get() {
Some(value) => { (value) }, Some(value) => { (value) },
None => {}, None => {},
} }
@ -198,24 +198,24 @@ impl Button {
&self.button_type &self.button_type
} }
pub fn name(&self) -> &Option<String> { pub fn name(&self) -> &AttributeValue {
self.name.option() &self.name
} }
pub fn value(&self) -> &Option<String> { pub fn value(&self) -> &AttributeValue {
self.value.option() &self.value
} }
pub fn autofocus(&self) -> &Option<String> { pub fn autofocus(&self) -> &AttributeValue {
self.autofocus.option() &self.autofocus
} }
pub fn disabled(&self) -> &Option<String> { pub fn disabled(&self) -> &AttributeValue {
self.disabled.option() &self.disabled
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -5,16 +5,16 @@ pub const DATE_COMPONENT: &str = "pagetop::component::form::date";
pub struct Date { pub struct Date {
renderable : fn() -> bool, renderable : fn() -> bool,
weight : isize, weight : isize,
name : OptAttr, name : AttributeValue,
value : OptAttr, value : AttributeValue,
label : OptAttr, label : AttributeValue,
placeholder : OptAttr, placeholder : AttributeValue,
autofocus : OptAttr, autofocus : AttributeValue,
autocomplete: OptAttr, autocomplete: AttributeValue,
disabled : OptAttr, disabled : AttributeValue,
readonly : OptAttr, readonly : AttributeValue,
required : OptAttr, required : AttributeValue,
help_text : OptAttr, help_text : AttributeValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -24,16 +24,16 @@ impl ComponentTrait for Date {
Date { Date {
renderable : render_always, renderable : render_always,
weight : 0, weight : 0,
name : OptAttr::new(), name : AttributeValue::new(),
value : OptAttr::new(), value : AttributeValue::new(),
label : OptAttr::new(), label : AttributeValue::new(),
placeholder : OptAttr::new(), placeholder : AttributeValue::new(),
autofocus : OptAttr::new(), autofocus : AttributeValue::new(),
autocomplete: OptAttr::new(), autocomplete: AttributeValue::new(),
disabled : OptAttr::new(), disabled : AttributeValue::new(),
readonly : OptAttr::new(), readonly : AttributeValue::new(),
required : OptAttr::new(), required : AttributeValue::new(),
help_text : OptAttr::new(), help_text : AttributeValue::new(),
classes : Classes::new_with_default("form-item"), classes : Classes::new_with_default("form-item"),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -53,16 +53,16 @@ impl ComponentTrait for Date {
} }
fn default_render(&self, _: &mut InContext) -> Markup { fn default_render(&self, _: &mut InContext) -> Markup {
let id = match self.name() { let id = match self.name().get() {
Some(name) => Some(concat_string!("edit-", name)), Some(name) => Some(concat_string!("edit-", name)),
None => None, None => None,
}; };
html! { html! {
div class=[self.classes()] { div class=[self.classes().get()] {
@match self.label() { @match self.label().get() {
Some(label) => label class="form-label" for=[&id] { Some(label) => label class="form-label" for=[&id] {
(label) " " (label) " "
@match self.required() { @match self.required().get() {
Some(_) => span Some(_) => span
class="form-required" class="form-required"
title="Este campo es obligatorio." { "*" } " ", title="Este campo es obligatorio." { "*" } " ",
@ -75,15 +75,15 @@ impl ComponentTrait for Date {
type="date" type="date"
id=[id] id=[id]
class="form-control" class="form-control"
name=[self.name()] name=[self.name().get()]
value=[self.value()] value=[self.value().get()]
placeholder=[self.placeholder()] placeholder=[self.placeholder().get()]
autofocus=[self.autofocus()] autofocus=[self.autofocus().get()]
autocomplete=[self.autocomplete()] autocomplete=[self.autocomplete().get()]
readonly=[self.readonly()] readonly=[self.readonly().get()]
required=[self.required()] required=[self.required().get()]
disabled=[self.disabled()]; disabled=[self.disabled().get()];
@match self.help_text() { @match self.help_text().get() {
Some(help_text) => div class="form-text" { (help_text) }, Some(help_text) => div class="form-text" { (help_text) },
None => {} None => {}
} }
@ -263,48 +263,48 @@ impl Date {
// Date GETTERS. // Date GETTERS.
pub fn name(&self) -> &Option<String> { pub fn name(&self) -> &AttributeValue {
self.name.option() &self.name
} }
pub fn value(&self) -> &Option<String> { pub fn value(&self) -> &AttributeValue {
self.value.option() &self.value
} }
pub fn label(&self) -> &Option<String> { pub fn label(&self) -> &AttributeValue {
self.label.option() &self.label
} }
pub fn placeholder(&self) -> &Option<String> { pub fn placeholder(&self) -> &AttributeValue {
self.placeholder.option() &self.placeholder
} }
pub fn autofocus(&self) -> &Option<String> { pub fn autofocus(&self) -> &AttributeValue {
self.autofocus.option() &self.autofocus
} }
pub fn autocomplete(&self) -> &Option<String> { pub fn autocomplete(&self) -> &AttributeValue {
self.autocomplete.option() &self.autocomplete
} }
pub fn disabled(&self) -> &Option<String> { pub fn disabled(&self) -> &AttributeValue {
self.disabled.option() &self.disabled
} }
pub fn readonly(&self) -> &Option<String> { pub fn readonly(&self) -> &AttributeValue {
self.readonly.option() &self.readonly
} }
pub fn required(&self) -> &Option<String> { pub fn required(&self) -> &AttributeValue {
self.required.option() &self.required
} }
pub fn help_text(&self) -> &Option<String> { pub fn help_text(&self) -> &AttributeValue {
self.help_text.option() &self.help_text
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -8,10 +8,10 @@ pub struct Form {
renderable: fn() -> bool, renderable: fn() -> bool,
weight : isize, weight : isize,
elements : ComponentsBundle, elements : ComponentsBundle,
action : OptAttr, action : AttributeValue,
charset : OptAttr, charset : AttributeValue,
method : FormMethod, method : FormMethod,
id : OptIden, id : IdentifierValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -22,10 +22,10 @@ impl ComponentTrait for Form {
renderable: render_always, renderable: render_always,
weight : 0, weight : 0,
elements : ComponentsBundle::new(), elements : ComponentsBundle::new(),
action : OptAttr::new(), action : AttributeValue::new(),
charset : OptAttr::new_with_value("UTF-8"), charset : AttributeValue::new_with_value("UTF-8"),
method : FormMethod::Post, method : FormMethod::Post,
id : OptIden::new(), id : IdentifierValue::new(),
classes : Classes::new_with_default("form"), classes : Classes::new_with_default("form"),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -50,11 +50,11 @@ impl ComponentTrait for Form {
}; };
html! { html! {
form form
id=[self.id()] id=[self.id().get()]
class=[self.classes()] class=[self.classes().get()]
action=[self.action()] action=[self.action().get()]
method=[method] method=[method]
accept-charset=[self.charset()] accept-charset=[self.charset().get()]
{ {
div { (self.elements().render(context)) } div { (self.elements().render(context)) }
} }
@ -169,24 +169,24 @@ impl Form {
// Form GETTERS. // Form GETTERS.
pub fn action(&self) -> &Option<String> { pub fn action(&self) -> &AttributeValue {
self.action.option() &self.action
} }
pub fn charset(&self) -> &Option<String> { pub fn charset(&self) -> &AttributeValue {
self.charset.option() &self.charset
} }
pub fn method(&self) -> &FormMethod { pub fn method(&self) -> &FormMethod {
&self.method &self.method
} }
pub fn id(&self) -> &Option<String> { pub fn id(&self) -> &IdentifierValue {
self.id.option() &self.id
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -4,16 +4,16 @@ pub const HIDDEN_COMPONENT: &str = "pagetop::component::form::hidden";
pub struct Hidden { pub struct Hidden {
weight: isize, weight: isize,
name : OptIden, name : IdentifierValue,
value : OptAttr, value : AttributeValue,
} }
impl ComponentTrait for Hidden { impl ComponentTrait for Hidden {
fn new() -> Self { fn new() -> Self {
Hidden { Hidden {
weight: 0, weight: 0,
name : OptIden::new(), name : IdentifierValue::new(),
value : OptAttr::new(), value : AttributeValue::new(),
} }
} }
@ -26,12 +26,12 @@ impl ComponentTrait for Hidden {
} }
fn default_render(&self, _: &mut InContext) -> Markup { fn default_render(&self, _: &mut InContext) -> Markup {
let id = match self.name() { let id = match self.name().get() {
Some(name) => Some(concat_string!("value-", name)), Some(name) => Some(concat_string!("value-", name)),
_ => None _ => None
}; };
html! { html! {
input type="hidden" id=[id] name=[self.name()] value=[self.value()]; input type="hidden" id=[id] name=[self.name().get()] value=[self.value().get()];
} }
} }
@ -85,11 +85,11 @@ impl Hidden {
// Hidden GETTERS. // Hidden GETTERS.
pub fn name(&self) -> &Option<String> { pub fn name(&self) -> &IdentifierValue {
self.name.option() &self.name
} }
pub fn value(&self) -> &Option<String> { pub fn value(&self) -> &AttributeValue {
self.value.option() &self.value
} }
} }

View file

@ -8,19 +8,19 @@ pub struct Input {
renderable : fn() -> bool, renderable : fn() -> bool,
weight : isize, weight : isize,
input_type : InputType, input_type : InputType,
name : OptIden, name : IdentifierValue,
value : OptAttr, value : AttributeValue,
label : OptAttr, label : AttributeValue,
size : Option<u16>, size : Option<u16>,
minlength : Option<u16>, minlength : Option<u16>,
maxlength : Option<u16>, maxlength : Option<u16>,
placeholder : OptAttr, placeholder : AttributeValue,
autofocus : OptAttr, autofocus : AttributeValue,
autocomplete: OptAttr, autocomplete: AttributeValue,
disabled : OptAttr, disabled : AttributeValue,
readonly : OptAttr, readonly : AttributeValue,
required : OptAttr, required : AttributeValue,
help_text : OptAttr, help_text : AttributeValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -31,19 +31,19 @@ impl ComponentTrait for Input {
renderable : render_always, renderable : render_always,
weight : 0, weight : 0,
input_type : InputType::Textfield, input_type : InputType::Textfield,
name : OptIden::new(), name : IdentifierValue::new(),
value : OptAttr::new(), value : AttributeValue::new(),
label : OptAttr::new(), label : AttributeValue::new(),
size : Some(60), size : Some(60),
minlength : None, minlength : None,
maxlength : Some(128), maxlength : Some(128),
placeholder : OptAttr::new(), placeholder : AttributeValue::new(),
autofocus : OptAttr::new(), autofocus : AttributeValue::new(),
autocomplete: OptAttr::new(), autocomplete: AttributeValue::new(),
disabled : OptAttr::new(), disabled : AttributeValue::new(),
readonly : OptAttr::new(), readonly : AttributeValue::new(),
required : OptAttr::new(), required : AttributeValue::new(),
help_text : OptAttr::new(), help_text : AttributeValue::new(),
classes : Classes::new_with_default("form-item"), classes : Classes::new_with_default("form-item"),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -71,16 +71,16 @@ impl ComponentTrait for Input {
InputType::Textfield => "text", InputType::Textfield => "text",
InputType::Url => "url", InputType::Url => "url",
}; };
let id = match self.name() { let id = match self.name().get() {
Some(name) => Some(concat_string!("edit-", name)), Some(name) => Some(concat_string!("edit-", name)),
None => None, None => None,
}; };
html! { html! {
div class=[self.classes()] { div class=[self.classes().get()] {
@match self.label() { @match self.label().get() {
Some(label) => label class="form-label" for=[&id] { Some(label) => label class="form-label" for=[&id] {
(label) " " (label) " "
@match self.required() { @match self.required().get() {
Some(_) => span Some(_) => span
class="form-required" class="form-required"
title="Este campo es obligatorio." { "*" } " ", title="Este campo es obligatorio." { "*" } " ",
@ -93,18 +93,18 @@ impl ComponentTrait for Input {
type=(type_input) type=(type_input)
id=[id] id=[id]
class="form-control" class="form-control"
name=[self.name()] name=[self.name().get()]
value=[self.value()] value=[self.value().get()]
size=[self.size()] size=[self.size()]
minlength=[self.minlength()] minlength=[self.minlength()]
maxlength=[self.maxlength()] maxlength=[self.maxlength()]
placeholder=[self.placeholder()] placeholder=[self.placeholder().get()]
autofocus=[self.autofocus()] autofocus=[self.autofocus().get()]
autocomplete=[self.autocomplete()] autocomplete=[self.autocomplete().get()]
readonly=[self.readonly()] readonly=[self.readonly().get()]
required=[self.required()] required=[self.required().get()]
disabled=[self.disabled()]; disabled=[self.disabled().get()];
@match self.help_text() { @match self.help_text().get() {
Some(help_text) => div class="form-text" { (help_text) }, Some(help_text) => div class="form-text" { (help_text) },
None => {} None => {}
} }
@ -360,16 +360,16 @@ impl Input {
&self.input_type &self.input_type
} }
pub fn name(&self) -> &Option<String> { pub fn name(&self) -> &IdentifierValue {
self.name.option() &self.name
} }
pub fn value(&self) -> &Option<String> { pub fn value(&self) -> &AttributeValue {
self.value.option() &self.value
} }
pub fn label(&self) -> &Option<String> { pub fn label(&self) -> &AttributeValue {
self.label.option() &self.label
} }
pub fn size(&self) -> Option<u16> { pub fn size(&self) -> Option<u16> {
@ -384,36 +384,36 @@ impl Input {
self.maxlength self.maxlength
} }
pub fn placeholder(&self) -> &Option<String> { pub fn placeholder(&self) -> &AttributeValue {
self.placeholder.option() &self.placeholder
} }
pub fn autofocus(&self) -> &Option<String> { pub fn autofocus(&self) -> &AttributeValue {
self.autofocus.option() &self.autofocus
} }
pub fn autocomplete(&self) -> &Option<String> { pub fn autocomplete(&self) -> &AttributeValue {
self.autocomplete.option() &self.autocomplete
} }
pub fn disabled(&self) -> &Option<String> { pub fn disabled(&self) -> &AttributeValue {
self.disabled.option() &self.disabled
} }
pub fn readonly(&self) -> &Option<String> { pub fn readonly(&self) -> &AttributeValue {
self.readonly.option() &self.readonly
} }
pub fn required(&self) -> &Option<String> { pub fn required(&self) -> &AttributeValue {
self.required.option() &self.required
} }
pub fn help_text(&self) -> &Option<String> { pub fn help_text(&self) -> &AttributeValue {
self.help_text.option() &self.help_text
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -6,7 +6,7 @@ pub struct Column {
renderable: fn() -> bool, renderable: fn() -> bool,
weight : isize, weight : isize,
components: ComponentsBundle, components: ComponentsBundle,
id : OptIden, id : IdentifierValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -17,7 +17,7 @@ impl ComponentTrait for Column {
renderable: render_always, renderable: render_always,
weight : 0, weight : 0,
components: ComponentsBundle::new(), components: ComponentsBundle::new(),
id : OptIden::new(), id : IdentifierValue::new(),
classes : Classes::new_with_default("col"), classes : Classes::new_with_default("col"),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -37,7 +37,7 @@ impl ComponentTrait for Column {
fn default_render(&self, context: &mut InContext) -> Markup { fn default_render(&self, context: &mut InContext) -> Markup {
html! { html! {
div id=[self.id()] class=[self.classes()] { div id=[self.id().get()] class=[self.classes().get()] {
(self.components().render(context)) (self.components().render(context))
} }
} }
@ -121,12 +121,12 @@ impl Column {
// Column GETTERS. // Column GETTERS.
pub fn id(&self) -> &Option<String> { pub fn id(&self) -> &IdentifierValue {
self.id.option() &self.id
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -6,7 +6,7 @@ pub struct Row {
renderable: fn() -> bool, renderable: fn() -> bool,
weight : isize, weight : isize,
columns : ComponentsBundle, columns : ComponentsBundle,
id : OptIden, id : IdentifierValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -17,7 +17,7 @@ impl ComponentTrait for Row {
renderable: render_always, renderable: render_always,
weight : 0, weight : 0,
columns : ComponentsBundle::new(), columns : ComponentsBundle::new(),
id : OptIden::new(), id : IdentifierValue::new(),
classes : Classes::new_with_default("row"), classes : Classes::new_with_default("row"),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -37,7 +37,7 @@ impl ComponentTrait for Row {
fn default_render(&self, context: &mut InContext) -> Markup { fn default_render(&self, context: &mut InContext) -> Markup {
html! { html! {
div id=[self.id()] class=[self.classes()] { div id=[self.id().get()] class=[self.classes().get()] {
(self.columns().render(context)) (self.columns().render(context))
} }
} }
@ -121,12 +121,12 @@ impl Row {
// Row GETTERS. // Row GETTERS.
pub fn id(&self) -> &Option<String> { pub fn id(&self) -> &IdentifierValue {
self.id.option() &self.id
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -19,7 +19,7 @@ pub struct Heading {
heading : HeadingType, heading : HeadingType,
html : Markup, html : Markup,
display : HeadingDisplay, display : HeadingDisplay,
id : OptIden, id : IdentifierValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -32,7 +32,7 @@ impl ComponentTrait for Heading {
heading : HeadingType::H1, heading : HeadingType::H1,
html : html! {}, html : html! {},
display : HeadingDisplay::Normal, display : HeadingDisplay::Normal,
id : OptIden::new(), id : IdentifierValue::new(),
classes : Classes::new(), classes : Classes::new(),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -51,13 +51,15 @@ impl ComponentTrait for Heading {
} }
fn default_render(&self, _: &mut InContext) -> Markup { fn default_render(&self, _: &mut InContext) -> Markup {
let id = self.id().get();
let classes = self.classes().get();
html! { @match &self.heading() { html! { @match &self.heading() {
HeadingType::H1 => h1 id=[self.id()] class=[self.classes()] { (*self.html()) }, HeadingType::H1 => h1 id=[id] class=[classes] { (*self.html()) },
HeadingType::H2 => h2 id=[self.id()] class=[self.classes()] { (*self.html()) }, HeadingType::H2 => h2 id=[id] class=[classes] { (*self.html()) },
HeadingType::H3 => h3 id=[self.id()] class=[self.classes()] { (*self.html()) }, HeadingType::H3 => h3 id=[id] class=[classes] { (*self.html()) },
HeadingType::H4 => h4 id=[self.id()] class=[self.classes()] { (*self.html()) }, HeadingType::H4 => h4 id=[id] class=[classes] { (*self.html()) },
HeadingType::H5 => h5 id=[self.id()] class=[self.classes()] { (*self.html()) }, HeadingType::H5 => h5 id=[id] class=[classes] { (*self.html()) },
HeadingType::H6 => h6 id=[self.id()] class=[self.classes()] { (*self.html()) }, HeadingType::H6 => h6 id=[id] class=[classes] { (*self.html()) },
}} }}
} }
@ -201,12 +203,12 @@ impl Heading {
&self.display &self.display
} }
pub fn id(&self) -> &Option<String> { pub fn id(&self) -> &IdentifierValue {
self.id.option() &self.id
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -6,7 +6,7 @@ pub struct Icon {
renderable: fn() -> bool, renderable: fn() -> bool,
weight : isize, weight : isize,
classes : Classes, classes : Classes,
inline_styles: InlineStyles, layout : Layout,
} }
impl ComponentTrait for Icon { impl ComponentTrait for Icon {
@ -15,7 +15,7 @@ impl ComponentTrait for Icon {
renderable: render_always, renderable: render_always,
weight : 0, weight : 0,
classes : Classes::new_with_default("bi-question-circle-fill"), classes : Classes::new_with_default("bi-question-circle-fill"),
inline_styles: InlineStyles::new(), layout : Layout::new(),
} }
} }
@ -37,7 +37,7 @@ impl ComponentTrait for Icon {
"/theme/icons/bootstrap-icons.css?ver=1.8.2" "/theme/icons/bootstrap-icons.css?ver=1.8.2"
)); ));
html! { i class=[self.classes()] style=[self.inline_styles()] {}; } html! { i class=[self.classes().get()] style=[self.layout().get()] {}; }
} }
fn as_ref_any(&self) -> &dyn AnyComponent { fn as_ref_any(&self) -> &dyn AnyComponent {
@ -76,8 +76,8 @@ impl Icon {
self self
} }
pub fn with_inline_style(mut self, style: &str, value: Option<&str>) -> Self { pub fn with_layout(mut self, property: LayoutProperty, value: LayoutUnit) -> Self {
self.alter_inline_style(style, value); self.alter_layout(property, value);
self self
} }
@ -103,18 +103,18 @@ impl Icon {
self self
} }
pub fn alter_inline_style(&mut self, style: &str, value: Option<&str>) -> &mut Self { pub fn alter_layout(&mut self, property: LayoutProperty, value: LayoutUnit) -> &mut Self {
self.inline_styles.add_style(style, value); self.layout.add(property, value);
self self
} }
// Icon GETTERS. // Icon GETTERS.
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn inline_styles(&self) -> Option<String> { pub fn layout(&self) -> &Layout {
self.inline_styles.option() &self.layout
} }
} }

View file

@ -5,8 +5,8 @@ pub const IMAGE_COMPONENT: &str = "pagetop::component::image";
pub struct Image { pub struct Image {
renderable: fn() -> bool, renderable: fn() -> bool,
weight : isize, weight : isize,
source : OptAttr, source : AttributeValue,
id : OptIden, id : IdentifierValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -16,8 +16,8 @@ impl ComponentTrait for Image {
Image { Image {
renderable: render_always, renderable: render_always,
weight : 0, weight : 0,
source : OptAttr::new(), source : AttributeValue::new(),
id : OptIden::new(), id : IdentifierValue::new(),
classes : Classes::new_with_default("img-fluid"), classes : Classes::new_with_default("img-fluid"),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -38,9 +38,9 @@ impl ComponentTrait for Image {
fn default_render(&self, _: &mut InContext) -> Markup { fn default_render(&self, _: &mut InContext) -> Markup {
html! { html! {
img img
src=[self.source()] src=[self.source().get()]
id=[self.id()] id=[self.id().get()]
class=[self.classes()]; class=[self.classes().get()];
} }
} }
@ -124,16 +124,16 @@ impl Image {
// Image GETTERS. // Image GETTERS.
pub fn source(&self) -> &Option<String> { pub fn source(&self) -> &AttributeValue {
self.source.option() &self.source
} }
pub fn id(&self) -> &Option<String> { pub fn id(&self) -> &IdentifierValue {
self.id.option() &self.id
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -177,7 +177,7 @@ pub struct Menu {
renderable: fn() -> bool, renderable: fn() -> bool,
weight : isize, weight : isize,
items : ComponentsBundle, items : ComponentsBundle,
id : OptIden, id : IdentifierValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -188,7 +188,7 @@ impl ComponentTrait for Menu {
renderable: render_always, renderable: render_always,
weight : 0, weight : 0,
items : ComponentsBundle::new(), items : ComponentsBundle::new(),
id : OptIden::new(), id : IdentifierValue::new(),
classes : Classes::new_with_default("sm sm-clean"), classes : Classes::new_with_default("sm sm-clean"),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -221,7 +221,7 @@ impl ComponentTrait for Menu {
let id = context.required_id::<Menu>(self.id()); let id = context.required_id::<Menu>(self.id());
html! { html! {
ul id=(id) class=[self.classes()] { ul id=(id) class=[self.classes().get()] {
(self.items().render(context)) (self.items().render(context))
} }
script type="text/javascript" defer { script type="text/javascript" defer {
@ -311,12 +311,12 @@ impl Menu {
// Menu GETTERS. // Menu GETTERS.
pub fn id(&self) -> &Option<String> { pub fn id(&self) -> &IdentifierValue {
self.id.option() &self.id
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -16,7 +16,7 @@ pub struct Paragraph {
weight : isize, weight : isize,
html : Markup, html : Markup,
display : ParagraphDisplay, display : ParagraphDisplay,
id : OptIden, id : IdentifierValue,
classes : Classes, classes : Classes,
template : String, template : String,
} }
@ -28,7 +28,7 @@ impl ComponentTrait for Paragraph {
weight : 0, weight : 0,
html : html! {}, html : html! {},
display : ParagraphDisplay::Normal, display : ParagraphDisplay::Normal,
id : OptIden::new(), id : IdentifierValue::new(),
classes : Classes::new(), classes : Classes::new(),
template : "default".to_owned(), template : "default".to_owned(),
} }
@ -48,7 +48,7 @@ impl ComponentTrait for Paragraph {
fn default_render(&self, _: &mut InContext) -> Markup { fn default_render(&self, _: &mut InContext) -> Markup {
html! { html! {
p id=[self.id()] class=[self.classes()] { (*self.html()) } p id=[self.id().get()] class=[self.classes().get()] { (*self.html()) }
} }
} }
@ -158,12 +158,12 @@ impl Paragraph {
&self.display &self.display
} }
pub fn id(&self) -> &Option<String> { pub fn id(&self) -> &IdentifierValue {
self.id.option() &self.id
} }
pub fn classes(&self) -> &Option<String> { pub fn classes(&self) -> &Classes {
self.classes.option() &self.classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {

View file

@ -68,7 +68,9 @@ fn hello_world() -> Container {
.add(Anchor::button("#", .add(Anchor::button("#",
html! { html! {
("Get quote") ("Get quote")
}).with_left_icon( }).with_layout(
LayoutProperty::MarginLeft, LayoutUnit::Px(8)
).with_left_icon(
Icon::with("envelope-open-heart-fill") Icon::with("envelope-open-heart-fill")
) )
) )

View file

@ -97,8 +97,8 @@ impl InContext {
// InContext EXTRAS. // InContext EXTRAS.
pub fn required_id<T>(&mut self, id: &Option<String>) -> String { pub fn required_id<T>(&mut self, id: &IdentifierValue) -> String {
match id { match id.get() {
Some(id) => id.to_string(), Some(id) => id.to_string(),
None => { None => {
let prefix = util::single_type_name::<T>() let prefix = util::single_type_name::<T>()

View file

@ -39,14 +39,14 @@ pub trait ThemeTrait: BaseTheme + Send + Sync {
head { head {
meta charset="utf-8"; meta charset="utf-8";
@match page.title() { @match page.title().get() {
Some(t) => title { Some(t) => title {
(concat_string!(SETTINGS.app.name, " | ", t)) (concat_string!(SETTINGS.app.name, " | ", t))
}, },
None => title { (SETTINGS.app.name) } None => title { (SETTINGS.app.name) }
} }
@match page.description() { @match page.description().get() {
Some(d) => meta name="description" content=(d);, Some(d) => meta name="description" content=(d);,
None => {} None => {}
} }
@ -61,7 +61,7 @@ pub trait ThemeTrait: BaseTheme + Send + Sync {
fn render_page_body(&self, page: &mut Page) -> Markup { fn render_page_body(&self, page: &mut Page) -> Markup {
html! { html! {
body class=[page.body_classes()] { body class=[page.body_classes().get()] {
@match page.template() { @match page.template() {
"admin" => { "admin" => {
@for region in &["top-menu", "side-menu", "content"] { @for region in &["top-menu", "side-menu", "content"] {

View file

@ -8,14 +8,14 @@ pub use assets::stylesheet::StyleSheet;
mod favicon; mod favicon;
pub use favicon::Favicon; pub use favicon::Favicon;
mod optiden; mod attribute;
pub use optiden::OptIden; pub use attribute::AttributeValue;
mod optattr; mod identifier;
pub use optattr::OptAttr; pub use identifier::IdentifierValue;
mod classes; mod classes;
pub use classes::{Classes, ClassesOp}; pub use classes::{Classes, ClassesOp};
mod inline_styles; mod layout;
pub use inline_styles::InlineStyles; pub use layout::{Layout, LayoutProperty, LayoutUnit};

View file

@ -0,0 +1,26 @@
pub struct AttributeValue(String);
impl AttributeValue {
pub fn new() -> Self {
AttributeValue("".to_owned())
}
pub fn new_with_value(value: &str) -> Self {
let mut attr = Self::new();
attr.with_value(value);
attr
}
pub fn with_value(&mut self, value: &str) -> &mut Self {
self.0 = value.trim().to_owned();
self
}
pub fn get(&self) -> Option<String> {
if self.0.is_empty() {
None
} else {
Some(self.0.to_owned())
}
}
}

View file

@ -14,7 +14,6 @@ pub enum ClassesOp {
pub struct Classes { pub struct Classes {
default: String, default: String,
added : String, added : String,
option : Option<String>,
} }
impl Classes { impl Classes {
@ -22,7 +21,6 @@ impl Classes {
Classes { Classes {
default: "".to_owned(), default: "".to_owned(),
added : "".to_owned(), added : "".to_owned(),
option : None,
} }
} }
@ -81,11 +79,14 @@ impl Classes {
self.default = classes.to_owned() self.default = classes.to_owned()
}, },
} }
self.option = Some(concat_string!(self.default, " ", self.added).trim().to_owned());
self self
} }
pub fn option(&self) -> &Option<String> { pub fn get(&self) -> Option<String> {
&self.option if self.default.is_empty() && self.added.is_empty() {
None
} else {
Some(concat_string!(self.default, " ", self.added).trim().to_owned())
}
} }
} }

View file

@ -0,0 +1,26 @@
pub struct IdentifierValue(String);
impl IdentifierValue {
pub fn new() -> Self {
IdentifierValue("".to_owned())
}
pub fn new_with_value(value: &str) -> Self {
let mut id = Self::new();
id.with_value(value);
id
}
pub fn with_value(&mut self, value: &str) -> &Self {
self.0 = value.trim().replace(" ", "_");
self
}
pub fn get(&self) -> Option<String> {
if self.0.is_empty() {
None
} else {
Some(self.0.to_owned())
}
}
}

View file

@ -1,46 +0,0 @@
use crate::concat_string;
struct Style {
property: String,
inline : String,
}
pub struct InlineStyles(Vec<Style>);
impl InlineStyles {
pub fn new() -> Self {
InlineStyles(Vec::new())
}
pub fn add_style(&mut self, property: &str, value: Option<&str>) -> &Self {
let property = property.trim();
match self.0.iter().position(|s| s.property.eq(property)) {
Some(pos) => {
self.0.remove(pos);
if let Some(value) = value {
self.0.insert(pos, Style {
property: property.to_owned(),
inline : concat_string!(property, ":", value.trim(), ";"),
});
}
},
_ => if let Some(value) = value {
self.0.push(Style {
property: property.to_owned(),
inline : concat_string!(property, ":", value.trim(), ";"),
});
}
}
self
}
pub fn option(&self) -> Option<String> {
if self.0.len() == 0 {
None
} else {
let mut inline = "".to_owned();
self.0.iter().for_each(|s| inline.push_str(s.inline.as_str()));
Some(inline)
}
}
}

124
pagetop/src/html/layout.rs Normal file
View file

@ -0,0 +1,124 @@
use crate::concat_string;
#[derive(Clone, Copy, PartialEq)]
pub enum LayoutProperty {
MarginBottom,
MarginLeft,
MarginRight,
MarginTop,
PaddingBottom,
PaddingLeft,
PaddingRight,
PaddingTop,
}
impl std::convert::AsRef<str> for LayoutProperty {
fn as_ref(&self) -> &str {
match *self {
LayoutProperty::MarginBottom => "margin-bottom",
LayoutProperty::MarginLeft => "margin-left",
LayoutProperty::MarginRight => "margin-right",
LayoutProperty::MarginTop => "margin-top",
LayoutProperty::PaddingBottom => "padding-bottom",
LayoutProperty::PaddingLeft => "padding-left",
LayoutProperty::PaddingRight => "padding-right",
LayoutProperty::PaddingTop => "padding-top",
}
}
}
// About pixels: Pixels (px) are relative to the viewing device. For low-dpi
// devices, 1px is one device pixel (dot) of the display. For printers and high
// resolution screens 1px implies multiple device pixels.
// About em: 2em means 2 times the size of the current font. The em and rem
// units are practical in creating perfectly scalable layout!
// About viewport: If the browser window size is 50cm wide, 1vw = 0.5cm.
#[derive(PartialEq)]
pub enum LayoutUnit {
Auto,
Cm(isize), // Centimeters.
In(isize), // Inches (1in = 96px = 2.54cm).
Mm(isize), // Millimeters.
Pc(isize), // Picas (1pc = 12pt).
Pt(isize), // Points (1pt = 1/72 of 1in).
Px(isize), // Pixels (1px = 1/96th of 1in).
RelEm(f32), // Relative to the font-size of the element.
RelPct(f32), // Percentage relative to the parent element.
RelRem(f32), // Relative to font-size of the root element.
RelVh(f32), // Relative to 1% of the height of the viewport.
RelVw(f32), // Relative to 1% of the width of the viewport.
UnSet,
}
impl LayoutUnit {
fn to_inline(&self, property: LayoutProperty) -> String {
match self {
LayoutUnit::Auto => concat_string!(property, ":auto;"),
LayoutUnit::Cm(value) => concat_string!(property, ":", value.to_string(), "cm;"),
LayoutUnit::In(value) => concat_string!(property, ":", value.to_string(), "in;"),
LayoutUnit::Mm(value) => concat_string!(property, ":", value.to_string(), "mm;"),
LayoutUnit::Pc(value) => concat_string!(property, ":", value.to_string(), "pc;"),
LayoutUnit::Pt(value) => concat_string!(property, ":", value.to_string(), "pt;"),
LayoutUnit::Px(value) => concat_string!(property, ":", value.to_string(), "px;"),
LayoutUnit::RelEm(value) => concat_string!(property, ":", value.to_string(), "em;"),
LayoutUnit::RelPct(value) => concat_string!(property, ":", value.to_string(), "%;"),
LayoutUnit::RelRem(value) => concat_string!(property, ":", value.to_string(), "rem;"),
LayoutUnit::RelVh(value) => concat_string!(property, ":", value.to_string(), "vh;"),
LayoutUnit::RelVw(value) => concat_string!(property, ":", value.to_string(), "vw;"),
_ => "".to_owned(),
}
}
}
struct Style {
property: LayoutProperty,
inline : String,
}
pub struct Layout(Vec<Style>);
impl Layout {
pub fn new() -> Self {
Layout(Vec::new())
}
pub fn add(&mut self, property: LayoutProperty, value: LayoutUnit) -> &Self {
match self.0.iter().position(|s| s.property.eq(&property)) {
Some(pos) => {
self.0.remove(pos);
if value != LayoutUnit::UnSet {
self.0.insert(pos, Style {
property,
inline: value.to_inline(property),
});
}
},
_ => if value != LayoutUnit::UnSet {
self.0.push(Style {
property,
inline: value.to_inline(property),
});
}
}
self
}
pub fn get(&self) -> Option<String> {
if self.0.len() == 0 {
None
} else {
let mut inline = "".to_owned();
self.0.iter().for_each(|s| inline.push_str(s.inline.as_str()));
Some(inline)
}
}
}

View file

@ -1,26 +0,0 @@
pub struct OptAttr(Option<String>);
impl OptAttr {
pub fn new() -> Self {
OptAttr(None)
}
pub fn new_with_value(value: &str) -> Self {
let mut option = Self::new();
option.with_value(value);
option
}
pub fn with_value(&mut self, value: &str) -> &mut Self {
let value = value.trim();
self.0 = match value.is_empty() {
true => None,
false => Some(value.to_owned()),
};
self
}
pub fn option(&self) -> &Option<String> {
&self.0
}
}

View file

@ -1,26 +0,0 @@
pub struct OptIden(Option<String>);
impl OptIden {
pub fn new() -> Self {
OptIden(None)
}
pub fn new_with_value(id: &str) -> Self {
let mut option = Self::new();
option.with_value(id);
option
}
pub fn with_value(&mut self, id: &str) -> &Self {
let id = id.trim();
self.0 = match id.is_empty() {
true => None,
false => Some(id.replace(" ", "_")),
};
self
}
pub fn option(&self) -> &Option<String> {
&self.0
}
}

View file

@ -37,10 +37,10 @@ static DEFAULT_DIRECTION: Lazy<Option<String>> = Lazy::new(|| {
pub enum TextDirection { Auto, LeftToRight, RightToLeft } pub enum TextDirection { Auto, LeftToRight, RightToLeft }
pub struct Page<'a> { pub struct Page<'a> {
language : OptAttr, language : AttributeValue,
direction : OptAttr, direction : AttributeValue,
title : OptAttr, title : AttributeValue,
description : OptAttr, description : AttributeValue,
context : InContext, context : InContext,
regions : HashMap<&'a str, ComponentsBundle>, regions : HashMap<&'a str, ComponentsBundle>,
body_classes: Classes, body_classes: Classes,
@ -52,15 +52,15 @@ impl<'a> Page<'a> {
pub fn new() -> Self { pub fn new() -> Self {
Page { Page {
language : match &*DEFAULT_LANGUAGE { language : match &*DEFAULT_LANGUAGE {
Some(language) => OptAttr::new_with_value(language), Some(language) => AttributeValue::new_with_value(language),
_ => OptAttr::new(), _ => AttributeValue::new(),
}, },
direction : match &*DEFAULT_DIRECTION { direction : match &*DEFAULT_DIRECTION {
Some(direction) => OptAttr::new_with_value(direction), Some(direction) => AttributeValue::new_with_value(direction),
_ => OptAttr::new(), _ => AttributeValue::new(),
}, },
title : OptAttr::new(), title : AttributeValue::new(),
description : OptAttr::new(), description : AttributeValue::new(),
context : InContext::new(), context : InContext::new(),
regions : common_components(), regions : common_components(),
body_classes: Classes::new_with_default("body"), body_classes: Classes::new_with_default("body"),
@ -119,28 +119,28 @@ impl<'a> Page<'a> {
// Page GETTERS. // Page GETTERS.
pub fn language(&self) -> &Option<String> { pub fn language(&self) -> &AttributeValue {
self.language.option() &self.language
} }
pub fn direction(&self) -> &Option<String> { pub fn direction(&self) -> &AttributeValue {
self.direction.option() &self.direction
} }
pub fn title(&self) -> &Option<String> { pub fn title(&self) -> &AttributeValue {
self.title.option() &self.title
} }
pub fn description(&self) -> &Option<String> { pub fn description(&self) -> &AttributeValue {
self.description.option() &self.description
} }
pub fn context(&mut self) -> &mut InContext { pub fn context(&mut self) -> &mut InContext {
&mut self.context &mut self.context
} }
pub fn body_classes(&self) -> &Option<String> { pub fn body_classes(&self) -> &Classes {
self.body_classes.option() &self.body_classes
} }
pub fn template(&self) -> &str { pub fn template(&self) -> &str {
@ -168,7 +168,7 @@ impl<'a> Page<'a> {
// Finalmente, renderizar la página. // Finalmente, renderizar la página.
return Ok(html! { return Ok(html! {
(DOCTYPE) (DOCTYPE)
html lang=[self.language()] dir=[self.direction()] { html lang=[self.language().get()] dir=[self.direction().get()] {
(head) (head)
(body) (body)
} }