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,
weight : isize,
anchor_type: AnchorType,
href : OptAttr,
href : AttributeValue,
html : Markup,
left_icon : AnchorIcon,
right_icon : AnchorIcon,
target : AnchorTarget,
id : OptIden,
id : IdentifierValue,
classes : Classes,
layout : Layout,
template : String,
}
@ -38,13 +39,14 @@ impl ComponentTrait for Anchor {
renderable : render_always,
weight : 0,
anchor_type: AnchorType::Link,
href : OptAttr::new(),
href : AttributeValue::new(),
html : html! {},
left_icon : AnchorIcon::new(),
right_icon : AnchorIcon::new(),
target : AnchorTarget::Default,
id : OptIden::new(),
id : IdentifierValue::new(),
classes : Classes::new(),
layout : Layout::new(),
template : "default".to_owned(),
}
}
@ -71,9 +73,10 @@ impl ComponentTrait for Anchor {
};
html! {
a
id=[self.id()]
class=[self.classes()]
href=[self.href()]
id=[self.id().get()]
class=[self.classes().get()]
style=[self.layout().get()]
href=[self.href().get()]
target=[target]
{
(self.left_icon().render(context))
@ -157,6 +160,11 @@ impl Anchor {
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 {
self.alter_template(template);
self
@ -195,13 +203,13 @@ impl Anchor {
pub fn alter_left_icon(&mut self, icon: Icon) -> &mut Self {
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
}
pub fn alter_right_icon(&mut self, icon: Icon) -> &mut Self {
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
}
@ -220,6 +228,11 @@ impl Anchor {
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 {
self.template = template.to_owned();
self
@ -231,8 +244,8 @@ impl Anchor {
&self.anchor_type
}
pub fn href(&self) -> &Option<String> {
self.href.option()
pub fn href(&self) -> &AttributeValue {
&self.href
}
pub fn html(&self) -> &Markup {
@ -251,12 +264,16 @@ impl Anchor {
&self.target
}
pub fn id(&self) -> &Option<String> {
self.id.option()
pub fn id(&self) -> &IdentifierValue {
&self.id
}
pub fn classes(&self) -> &Option<String> {
self.classes.option()
pub fn classes(&self) -> &Classes {
&self.classes
}
pub fn layout(&self) -> &Layout {
&self.layout
}
pub fn template(&self) -> &str {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,16 +4,16 @@ pub const HIDDEN_COMPONENT: &str = "pagetop::component::form::hidden";
pub struct Hidden {
weight: isize,
name : OptIden,
value : OptAttr,
name : IdentifierValue,
value : AttributeValue,
}
impl ComponentTrait for Hidden {
fn new() -> Self {
Hidden {
weight: 0,
name : OptIden::new(),
value : OptAttr::new(),
name : IdentifierValue::new(),
value : AttributeValue::new(),
}
}
@ -26,12 +26,12 @@ impl ComponentTrait for Hidden {
}
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)),
_ => None
};
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.
pub fn name(&self) -> &Option<String> {
self.name.option()
pub fn name(&self) -> &IdentifierValue {
&self.name
}
pub fn value(&self) -> &Option<String> {
self.value.option()
pub fn value(&self) -> &AttributeValue {
&self.value
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -3,19 +3,19 @@ use crate::prelude::*;
pub const ICON_COMPONENT: &str = "pagetop::component::icon";
pub struct Icon {
renderable : fn() -> bool,
weight : isize,
classes : Classes,
inline_styles: InlineStyles,
renderable: fn() -> bool,
weight : isize,
classes : Classes,
layout : Layout,
}
impl ComponentTrait for Icon {
fn new() -> Self {
Icon {
renderable : render_always,
weight : 0,
classes : Classes::new_with_default("bi-question-circle-fill"),
inline_styles: InlineStyles::new(),
renderable: render_always,
weight : 0,
classes : Classes::new_with_default("bi-question-circle-fill"),
layout : Layout::new(),
}
}
@ -37,7 +37,7 @@ impl ComponentTrait for Icon {
"/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 {
@ -76,8 +76,8 @@ impl Icon {
self
}
pub fn with_inline_style(mut self, style: &str, value: Option<&str>) -> Self {
self.alter_inline_style(style, value);
pub fn with_layout(mut self, property: LayoutProperty, value: LayoutUnit) -> Self {
self.alter_layout(property, value);
self
}
@ -103,18 +103,18 @@ impl Icon {
self
}
pub fn alter_inline_style(&mut self, style: &str, value: Option<&str>) -> &mut Self {
self.inline_styles.add_style(style, value);
pub fn alter_layout(&mut self, property: LayoutProperty, value: LayoutUnit) -> &mut Self {
self.layout.add(property, value);
self
}
// Icon GETTERS.
pub fn classes(&self) -> &Option<String> {
self.classes.option()
pub fn classes(&self) -> &Classes {
&self.classes
}
pub fn inline_styles(&self) -> Option<String> {
self.inline_styles.option()
pub fn layout(&self) -> &Layout {
&self.layout
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,14 +8,14 @@ pub use assets::stylesheet::StyleSheet;
mod favicon;
pub use favicon::Favicon;
mod optiden;
pub use optiden::OptIden;
mod attribute;
pub use attribute::AttributeValue;
mod optattr;
pub use optattr::OptAttr;
mod identifier;
pub use identifier::IdentifierValue;
mod classes;
pub use classes::{Classes, ClassesOp};
mod inline_styles;
pub use inline_styles::InlineStyles;
mod layout;
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 {
default: String,
added : String,
option : Option<String>,
}
impl Classes {
@ -22,7 +21,6 @@ impl Classes {
Classes {
default: "".to_owned(),
added : "".to_owned(),
option : None,
}
}
@ -81,11 +79,14 @@ impl Classes {
self.default = classes.to_owned()
},
}
self.option = Some(concat_string!(self.default, " ", self.added).trim().to_owned());
self
}
pub fn option(&self) -> &Option<String> {
&self.option
pub fn get(&self) -> Option<String> {
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 struct Page<'a> {
language : OptAttr,
direction : OptAttr,
title : OptAttr,
description : OptAttr,
language : AttributeValue,
direction : AttributeValue,
title : AttributeValue,
description : AttributeValue,
context : InContext,
regions : HashMap<&'a str, ComponentsBundle>,
body_classes: Classes,
@ -52,15 +52,15 @@ impl<'a> Page<'a> {
pub fn new() -> Self {
Page {
language : match &*DEFAULT_LANGUAGE {
Some(language) => OptAttr::new_with_value(language),
_ => OptAttr::new(),
Some(language) => AttributeValue::new_with_value(language),
_ => AttributeValue::new(),
},
direction : match &*DEFAULT_DIRECTION {
Some(direction) => OptAttr::new_with_value(direction),
_ => OptAttr::new(),
Some(direction) => AttributeValue::new_with_value(direction),
_ => AttributeValue::new(),
},
title : OptAttr::new(),
description : OptAttr::new(),
title : AttributeValue::new(),
description : AttributeValue::new(),
context : InContext::new(),
regions : common_components(),
body_classes: Classes::new_with_default("body"),
@ -119,28 +119,28 @@ impl<'a> Page<'a> {
// Page GETTERS.
pub fn language(&self) -> &Option<String> {
self.language.option()
pub fn language(&self) -> &AttributeValue {
&self.language
}
pub fn direction(&self) -> &Option<String> {
self.direction.option()
pub fn direction(&self) -> &AttributeValue {
&self.direction
}
pub fn title(&self) -> &Option<String> {
self.title.option()
pub fn title(&self) -> &AttributeValue {
&self.title
}
pub fn description(&self) -> &Option<String> {
self.description.option()
pub fn description(&self) -> &AttributeValue {
&self.description
}
pub fn context(&mut self) -> &mut InContext {
&mut self.context
}
pub fn body_classes(&self) -> &Option<String> {
self.body_classes.option()
pub fn body_classes(&self) -> &Classes {
&self.body_classes
}
pub fn template(&self) -> &str {
@ -168,7 +168,7 @@ impl<'a> Page<'a> {
// Finalmente, renderizar la página.
return Ok(html! {
(DOCTYPE)
html lang=[self.language()] dir=[self.direction()] {
html lang=[self.language().get()] dir=[self.direction().get()] {
(head)
(body)
}