Añade nuevas características a la página demo

This commit is contained in:
Manuel Cillero 2022-03-27 06:05:37 +02:00
parent 5b1064fda2
commit c6bbd565ab
33 changed files with 987 additions and 470 deletions

View file

@ -2,37 +2,37 @@ use pagetop::prelude::*;
use super::l;
pub async fn summary() -> app::Result<Markup> {
let top_menu = Menu::prepare()
let top_menu = Menu::new()
.add(MenuItem::label(l("module_fullname").as_str()))
.add(MenuItem::link("Opción 2", "https://www.google.es"))
.add(MenuItem::link_blank("Opción 3", "https://www.google.es"))
.add(MenuItem::submenu("Submenú 1", Menu::prepare()
.add(MenuItem::submenu("Submenú 1", Menu::new()
.add(MenuItem::label("Opción 1"))
.add(MenuItem::label("Opción 2"))
))
.add(MenuItem::separator())
.add(MenuItem::submenu("Submenú 2", Menu::prepare()
.add(MenuItem::submenu("Submenú 2", Menu::new()
.add(MenuItem::label("Opción 1"))
.add(MenuItem::label("Opción 2"))
))
.add(MenuItem::label("Opción 4"));
let side_menu = Menu::prepare()
let side_menu = Menu::new()
.add(MenuItem::label("Opción 1"))
.add(MenuItem::link("Opción 2", "https://www.google.es"))
.add(MenuItem::link_blank("Opción 3", "https://www.google.es"))
.add(MenuItem::submenu("Submenú 1", Menu::prepare()
.add(MenuItem::submenu("Submenú 1", Menu::new()
.add(MenuItem::label("Opción 1"))
.add(MenuItem::label("Opción 2"))
))
.add(MenuItem::separator())
.add(MenuItem::submenu("Submenú 2", Menu::prepare()
.add(MenuItem::submenu("Submenú 2", Menu::new()
.add(MenuItem::label("Opción 1"))
.add(MenuItem::label("Opción 2"))
))
.add(MenuItem::label("Opción 4"));
Page::prepare()
Page::new()
.using_theme("bootsier")
@ -40,12 +40,12 @@ pub async fn summary() -> app::Result<Markup> {
.add_to("top-menu", top_menu)
.add_to("content", Container::row()
.add(Container::column()
.add_to("content", grid::Row::new()
.add_column(grid::Column::new()
.add(side_menu)
)
.add(Container::column()
.add(Chunck::markup(html! {
.add_column(grid::Column::new()
.add(Chunck::with(html! {
p { "Columna 2"}
}))
)

View file

@ -35,7 +35,7 @@ impl ModuleTrait for NodeModule {
}
async fn node() -> app::Result<Markup> {
Page::prepare()
Page::new()
.with_title(
"Nodo"
)

View file

@ -32,7 +32,7 @@ impl ModuleTrait for UserModule {
}
fn form_login() -> impl PageComponent {
Form::prepare()
Form::new()
.with_id("user-login")
.add(form::Input::textfield()
.with_name("name")
@ -51,11 +51,11 @@ fn form_login() -> impl PageComponent {
}
async fn login() -> app::Result<Markup> {
Page::prepare()
Page::new()
.with_title(
"Identificación del usuario"
)
.add_to("content", Container::prepare()
.add_to("content", Container::new()
.with_id("welcome")
.add(form_login())
)

View file

@ -3,21 +3,21 @@ use crate::prelude::*;
pub struct Block {
renderable: fn() -> bool,
weight : i8,
id : Option<String>,
title : Option<String>,
markup : Vec<Markup>,
id : OptionId,
title : OptionAttr,
html : Vec<Markup>,
template : String,
}
impl PageComponent for Block {
fn prepare() -> Self {
fn new() -> Self {
Block {
renderable: always,
weight : 0,
id : None,
title : None,
markup : Vec::new(),
id : OptionId::none(),
title : OptionAttr::none(),
html : Vec::new(),
template : "default".to_owned(),
}
}
@ -31,15 +31,16 @@ impl PageComponent for Block {
}
fn default_render(&self, assets: &mut PageAssets) -> Markup {
let id = assets.serial_id(self.name(), self.id());
let id = assets.serial_id(self.name(), self.id.value());
let title = self.title.value();
html! {
div id=(id) class="block" {
@if self.title != None {
h2 class="block-title" { (self.title()) }
@if !title.is_empty() {
h2 class="block-title" { (title) }
}
div class="block-body" {
@for markup in self.markup.iter() {
(*markup)
@for html in self.html.iter() {
(*html)
}
}
}
@ -49,8 +50,8 @@ impl PageComponent for Block {
impl Block {
pub fn markup(markup: Markup) -> Self {
Block::prepare().add_markup(markup)
pub fn with(html: Markup) -> Self {
Block::new().add(html)
}
// Block BUILDER.
@ -66,17 +67,17 @@ impl Block {
}
pub fn with_id(mut self, id: &str) -> Self {
self.id = util::valid_id(id);
self.id.with_value(id);
self
}
pub fn with_title(mut self, title: &str) -> Self {
self.title = util::valid_str(title);
self.title.with_value(title);
self
}
pub fn add_markup(mut self, markup: Markup) -> Self {
self.markup.push(markup);
pub fn add(mut self, html: Markup) -> Self {
self.html.push(html);
self
}
@ -88,11 +89,11 @@ impl Block {
// Block GETTERS.
pub fn id(&self) -> &str {
util::assigned_str(&self.id)
self.id.value()
}
pub fn title(&self) -> &str {
util::assigned_str(&self.title)
self.title.value()
}
pub fn template(&self) -> &str {

View file

@ -3,17 +3,17 @@ use crate::prelude::*;
pub struct Chunck {
renderable: fn() -> bool,
weight : i8,
markup : Vec<Markup>,
html : Vec<Markup>,
template : String,
}
impl PageComponent for Chunck {
fn prepare() -> Self {
fn new() -> Self {
Chunck {
renderable: always,
weight : 0,
markup : Vec::new(),
html : Vec::new(),
template : "default".to_owned(),
}
}
@ -28,8 +28,8 @@ impl PageComponent for Chunck {
fn default_render(&self, _: &mut PageAssets) -> Markup {
html! {
@for markup in self.markup.iter() {
(*markup)
@for html in self.html.iter() {
(*html)
}
}
}
@ -37,8 +37,8 @@ impl PageComponent for Chunck {
impl Chunck {
pub fn markup(markup: Markup) -> Self {
Chunck::prepare().add_markup(markup)
pub fn with(html: Markup) -> Self {
Chunck::new().add(html)
}
// Chunck BUILDER.
@ -53,8 +53,8 @@ impl Chunck {
self
}
pub fn add_markup(mut self, markup: Markup) -> Self {
self.markup.push(markup);
pub fn add(mut self, html: Markup) -> Self {
self.html.push(html);
self
}

View file

@ -1,11 +1,11 @@
use crate::prelude::*;
enum ContainerType { Column, Row, Wrapper }
enum ContainerType { Header, Footer, Main, Section, Wrapper }
pub struct Container {
renderable: fn() -> bool,
weight : i8,
id : Option<String>,
id : OptionId,
container : ContainerType,
components: PageContainer,
template : String,
@ -13,11 +13,11 @@ pub struct Container {
impl PageComponent for Container {
fn prepare() -> Self {
fn new() -> Self {
Container {
renderable: always,
weight : 0,
id : None,
id : OptionId::none(),
container : ContainerType::Wrapper,
components: PageContainer::new(),
template : "default".to_owned(),
@ -33,14 +33,39 @@ impl PageComponent for Container {
}
fn default_render(&self, assets: &mut PageAssets) -> Markup {
let classes = match self.container {
ContainerType::Wrapper => "container",
ContainerType::Row => "row",
ContainerType::Column => "col",
};
html! {
div id=[&self.id] class=(classes) {
(self.components.render(assets))
match self.container {
ContainerType::Header => html! {
header id=[&self.id.option()] class="header" {
div class="container" {
(self.components.render(assets))
}
}
},
ContainerType::Footer => html! {
footer id=[&self.id.option()] class="footer" {
div class="container" {
(self.components.render(assets))
}
}
},
ContainerType::Main => html! {
main id=[&self.id.option()] class="main" {
div class="container" {
(self.components.render(assets))
}
}
},
ContainerType::Section => html! {
section id=[&self.id.option()] class="section" {
div class="container" {
(self.components.render(assets))
}
}
},
_ => html! {
div id=[&self.id.option()] class="container" {
(self.components.render(assets))
}
}
}
}
@ -48,16 +73,28 @@ impl PageComponent for Container {
impl Container {
pub fn row() -> Self {
let mut grid = Container::prepare();
grid.container = ContainerType::Row;
grid
pub fn header() -> Self {
let mut c = Container::new();
c.container = ContainerType::Header;
c
}
pub fn column() -> Self {
let mut grid = Container::prepare();
grid.container = ContainerType::Column;
grid
pub fn footer() -> Self {
let mut c = Container::new();
c.container = ContainerType::Footer;
c
}
pub fn main() -> Self {
let mut c = Container::new();
c.container = ContainerType::Main;
c
}
pub fn section() -> Self {
let mut c = Container::new();
c.container = ContainerType::Section;
c
}
// Container BUILDER.
@ -73,7 +110,7 @@ impl Container {
}
pub fn with_id(mut self, id: &str) -> Self {
self.id = util::valid_id(id);
self.id.with_value(id);
self
}
@ -90,7 +127,7 @@ impl Container {
// Container GETTERS.
pub fn id(&self) -> &str {
util::assigned_str(&self.id)
self.id.value()
}
pub fn template(&self) -> &str {

View file

@ -6,24 +6,24 @@ pub struct Button {
renderable : fn() -> bool,
weight : i8,
button_type: ButtonType,
name : Option<String>,
value : Option<String>,
autofocus : Option<String>,
disabled : Option<String>,
name : OptionAttr,
value : OptionAttr,
autofocus : OptionAttr,
disabled : OptionAttr,
template : String,
}
impl PageComponent for Button {
fn prepare() -> Self {
fn new() -> Self {
Button {
renderable : always,
weight : 0,
button_type: ButtonType::Button,
name : None,
value : None,
autofocus : None,
disabled : None,
name : OptionAttr::none(),
value : OptionAttr::none(),
autofocus : OptionAttr::none(),
disabled : OptionAttr::none(),
template : "default".to_owned(),
}
}
@ -42,7 +42,7 @@ impl PageComponent for Button {
ButtonType::Reset => ("reset", "btn btn-primary form-reset" ),
ButtonType::Submit => ("submit", "btn btn-primary form-submit")
};
let id_item = match &self.name {
let id_item = match &self.name.option() {
Some(name) => Some(format!("edit-{}", name)),
_ => None
};
@ -51,15 +51,12 @@ impl PageComponent for Button {
type=(button_type)
id=[&id_item]
class=(button_class)
name=[&self.name]
value=[&self.value]
autofocus=[&self.autofocus]
disabled=[&self.disabled]
name=[&self.name.option()]
value=[&self.value.option()]
autofocus=[&self.autofocus.option()]
disabled=[&self.disabled.option()]
{
@match &self.value {
Some(value) => (value),
_ => ""
};
(self.value.value())
}
}
}
@ -68,17 +65,17 @@ impl PageComponent for Button {
impl Button {
pub fn button(value: &str) -> Self {
Button::prepare().with_value(value)
Button::new().with_value(value)
}
pub fn reset(value: &str) -> Self {
let mut button = Button::prepare().with_value(value);
let mut button = Button::new().with_value(value);
button.button_type = ButtonType::Reset;
button
}
pub fn submit(value: &str) -> Self {
let mut button = Button::prepare().with_value(value);
let mut button = Button::new().with_value(value);
button.button_type = ButtonType::Submit;
button
}
@ -96,28 +93,28 @@ impl Button {
}
pub fn with_name(mut self, name: &str) -> Self {
self.name = util::valid_id(name);
self.name.with_value(name);
self
}
pub fn with_value(mut self, value: &str) -> Self {
self.value = util::valid_str(value);
self.value.with_value(value);
self
}
pub fn autofocus(mut self, toggle: bool) -> Self {
self.autofocus = match toggle {
true => Some("autofocus".to_owned()),
false => None
};
self.autofocus.with_value(match toggle {
true => "autofocus",
false => "",
});
self
}
pub fn disabled(mut self, toggle: bool) -> Self {
self.disabled = match toggle {
true => Some("disabled".to_owned()),
false => None
};
self.disabled.with_value(match toggle {
true => "disabled",
false => "",
});
self
}
@ -129,25 +126,19 @@ impl Button {
// Button GETTERS.
pub fn name(&self) -> &str {
util::assigned_str(&self.name)
self.name.value()
}
pub fn value(&self) -> &str {
util::assigned_str(&self.value)
self.value.value()
}
pub fn has_autofocus(&self) -> bool {
match &self.autofocus {
Some(_) => true,
_ => false
}
self.autofocus.has_value()
}
pub fn is_disabled(&self) -> bool {
match &self.disabled {
Some(_) => true,
_ => false
}
self.disabled.has_value()
}
pub fn template(&self) -> &str {

View file

@ -3,35 +3,35 @@ use crate::prelude::*;
pub struct Date {
renderable : fn() -> bool,
weight : i8,
name : Option<String>,
value : Option<String>,
label : Option<String>,
placeholder : Option<String>,
autofocus : Option<String>,
autocomplete: Option<String>,
disabled : Option<String>,
readonly : Option<String>,
required : Option<String>,
help_text : Option<String>,
name : OptionAttr,
value : OptionAttr,
label : OptionAttr,
placeholder : OptionAttr,
autofocus : OptionAttr,
autocomplete: OptionAttr,
disabled : OptionAttr,
readonly : OptionAttr,
required : OptionAttr,
help_text : OptionAttr,
template : String,
}
impl PageComponent for Date {
fn prepare() -> Self {
fn new() -> Self {
Date {
renderable : always,
weight : 0,
name : None,
value : None,
label : None,
placeholder : None,
autofocus : None,
autocomplete: None,
disabled : None,
readonly : None,
required : None,
help_text : None,
name : OptionAttr::none(),
value : OptionAttr::none(),
label : OptionAttr::none(),
placeholder : OptionAttr::none(),
autofocus : OptionAttr::none(),
autocomplete: OptionAttr::none(),
disabled : OptionAttr::none(),
readonly : OptionAttr::none(),
required : OptionAttr::none(),
help_text : OptionAttr::none(),
template : "default".to_owned(),
}
}
@ -45,7 +45,7 @@ impl PageComponent for Date {
}
fn default_render(&self, _: &mut PageAssets) -> Markup {
let (class_item, id_item) = match &self.name {
let (class_item, id_item) = match self.name.option() {
Some(name) => (
format!("form-item form-item-{} form-type-date", name),
Some(format!("edit-{}", name))
@ -57,10 +57,10 @@ impl PageComponent for Date {
};
html! {
div class=(class_item) {
@if self.label != None {
@if self.label.has_value() {
label class="form-label" for=[&id_item] {
(self.label()) " "
@if self.required != None {
(self.label.value()) " "
@if self.required.has_value() {
span
class="form-required"
title="Este campo es obligatorio."
@ -74,17 +74,17 @@ impl PageComponent for Date {
type="date"
id=[&id_item]
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];
@if self.help_text != None {
name=[&self.name.option()]
value=[&self.value.option()]
placeholder=[&self.placeholder.option()]
autofocus=[&self.autofocus.option()]
autocomplete=[&self.autocomplete.option()]
readonly=[&self.readonly.option()]
required=[&self.required.option()]
disabled=[&self.disabled.option()];
@if self.help_text.has_value() {
div class="form-text" {
(self.help_text())
(self.help_text.value())
}
}
}
@ -107,67 +107,67 @@ impl Date {
}
pub fn with_name(mut self, name: &str) -> Self {
self.name = util::valid_id(name);
self.name.with_value(name);
self
}
pub fn with_value(mut self, value: &str) -> Self {
self.value = util::valid_str(value);
self.value.with_value(value);
self
}
pub fn with_label(mut self, label: &str) -> Self {
self.label = util::valid_str(label);
self.label.with_value(label);
self
}
pub fn with_placeholder(mut self, placeholder: &str) -> Self {
self.placeholder = util::valid_str(placeholder);
self.placeholder.with_value(placeholder);
self
}
pub fn autofocus(mut self, toggle: bool) -> Self {
self.autofocus = match toggle {
true => Some("autofocus".to_owned()),
false => None
};
self.autofocus.with_value(match toggle {
true => "autofocus",
false => "",
});
self
}
pub fn autocomplete(mut self, toggle: bool) -> Self {
self.autocomplete = match toggle {
true => None,
false => Some("off".to_owned())
};
self.autocomplete.with_value(match toggle {
true => "",
false => "off",
});
self
}
pub fn disabled(mut self, toggle: bool) -> Self {
self.disabled = match toggle {
true => Some("disabled".to_owned()),
false => None
};
self.disabled.with_value(match toggle {
true => "disabled",
false => "",
});
self
}
pub fn readonly(mut self, toggle: bool) -> Self {
self.readonly = match toggle {
true => Some("readonly".to_owned()),
false => None
};
self.readonly.with_value(match toggle {
true => "readonly",
false => "",
});
self
}
pub fn required(mut self, toggle: bool) -> Self {
self.required = match toggle {
true => Some("required".to_owned()),
false => None
};
self.required.with_value(match toggle {
true => "required",
false => "",
});
self
}
pub fn with_help_text(mut self, help_text: &str) -> Self {
self.help_text = util::valid_str(help_text);
self.help_text.with_value(help_text);
self
}
@ -179,58 +179,43 @@ impl Date {
// Date GETTERS.
pub fn name(&self) -> &str {
util::assigned_str(&self.name)
self.name.value()
}
pub fn value(&self) -> &str {
util::assigned_str(&self.value)
self.value.value()
}
pub fn label(&self) -> &str {
util::assigned_str(&self.label)
self.label.value()
}
pub fn placeholder(&self) -> &str {
util::assigned_str(&self.placeholder)
self.placeholder.value()
}
pub fn has_autofocus(&self) -> bool {
match &self.autofocus {
Some(_) => true,
_ => false
}
self.autofocus.has_value()
}
pub fn has_autocomplete(&self) -> bool {
match &self.autocomplete {
Some(_) => false,
_ => true
}
!self.autocomplete.has_value()
}
pub fn is_disabled(&self) -> bool {
match &self.disabled {
Some(_) => true,
_ => false
}
self.disabled.has_value()
}
pub fn is_readonly(&self) -> bool {
match &self.readonly {
Some(_) => true,
_ => false
}
self.readonly.has_value()
}
pub fn is_required(&self) -> bool {
match &self.required {
Some(_) => true,
_ => false
}
self.required.has_value()
}
pub fn help_text(&self) -> &str {
util::assigned_str(&self.help_text)
self.help_text.value()
}
pub fn template(&self) -> &str {

View file

@ -5,24 +5,24 @@ pub enum FormMethod {Get, Post}
pub struct Form {
renderable: fn() -> bool,
weight : i8,
id : Option<String>,
action : Option<String>,
id : OptionId,
action : OptionAttr,
method : FormMethod,
charset : Option<String>,
charset : OptionAttr,
elements : PageContainer,
template : String,
}
impl PageComponent for Form {
fn prepare() -> Self {
fn new() -> Self {
Form {
renderable: always,
weight : 0,
id : None,
action : None,
id : OptionId::none(),
action : OptionAttr::none(),
method : FormMethod::Post,
charset : Some("UTF-8".to_owned()),
charset : OptionAttr::some("UTF-8"),
elements : PageContainer::new(),
template : "default".to_owned(),
}
@ -43,10 +43,10 @@ impl PageComponent for Form {
};
html! {
form
id=[&self.id]
action=[&self.action]
id=[&self.id.option()]
action=[&self.action.option()]
method=[method]
accept-charset=[&self.charset]
accept-charset=[&self.charset.option()]
{
div {
(self.elements.render(assets))
@ -71,12 +71,12 @@ impl Form {
}
pub fn with_id(mut self, id: &str) -> Self {
self.id = util::valid_id(id);
self.id.with_value(id);
self
}
pub fn with_action(mut self, action: &str) -> Self {
self.action = util::valid_str(action);
self.action.with_value(action);
self
}
@ -86,7 +86,7 @@ impl Form {
}
pub fn with_charset(mut self, charset: &str) -> Self {
self.charset = util::valid_str(charset);
self.charset.with_value(charset);
self
}
@ -103,11 +103,11 @@ impl Form {
// Form GETTERS.
pub fn id(&self) -> &str {
util::assigned_str(&self.id)
self.id.value()
}
pub fn action(&self) -> &str {
util::assigned_str(&self.action)
self.action.value()
}
pub fn method(&self) -> &str {
@ -118,7 +118,7 @@ impl Form {
}
pub fn charset(&self) -> &str {
util::assigned_str(&self.charset)
self.charset.value()
}
pub fn template(&self) -> &str {

View file

@ -2,17 +2,17 @@ use crate::prelude::*;
pub struct Hidden {
weight : i8,
name : Option<String>,
value : Option<String>,
name : OptionId,
value : OptionAttr,
}
impl PageComponent for Hidden {
fn prepare() -> Self {
fn new() -> Self {
Hidden {
weight : 0,
name : None,
value : None,
name : OptionId::none(),
value : OptionAttr::none(),
}
}
@ -21,7 +21,7 @@ impl PageComponent for Hidden {
}
fn default_render(&self, _: &mut PageAssets) -> Markup {
let id_item = match &self.name {
let id_item = match self.name.option() {
Some(name) => Some(format!("value-{}", name)),
_ => None
};
@ -29,8 +29,8 @@ impl PageComponent for Hidden {
input
type="hidden"
id=[&id_item]
name=[&self.name]
value=[&self.value];
name=[&self.name.option()]
value=[&self.value.option()];
}
}
}
@ -38,7 +38,7 @@ impl PageComponent for Hidden {
impl Hidden {
pub fn set(name: &str, value: &str) -> Self {
Hidden::prepare().with_name(name).with_value(value)
Hidden::new().with_name(name).with_value(value)
}
// Hidden BUILDER.
@ -49,22 +49,22 @@ impl Hidden {
}
pub fn with_name(mut self, name: &str) -> Self {
self.name = util::valid_id(name);
self.name.with_value(name);
self
}
pub fn with_value(mut self, value: &str) -> Self {
self.value = util::valid_str(value);
self.value.with_value(value);
self
}
// Hidden GETTERS.
pub fn name(&self) -> &str {
util::assigned_str(&self.name)
self.name.value()
}
pub fn value(&self) -> &str {
util::assigned_str(&self.value)
self.value.value()
}
}

View file

@ -6,42 +6,42 @@ pub struct Input {
renderable : fn() -> bool,
weight : i8,
input_type : InputType,
name : Option<String>,
value : Option<String>,
label : Option<String>,
name : OptionId,
value : OptionAttr,
label : OptionAttr,
size : Option<u16>,
minlength : Option<u16>,
maxlength : Option<u16>,
placeholder : Option<String>,
autofocus : Option<String>,
autocomplete: Option<String>,
disabled : Option<String>,
readonly : Option<String>,
required : Option<String>,
help_text : Option<String>,
placeholder : OptionAttr,
autofocus : OptionAttr,
autocomplete: OptionAttr,
disabled : OptionAttr,
readonly : OptionAttr,
required : OptionAttr,
help_text : OptionAttr,
template : String,
}
impl PageComponent for Input {
fn prepare() -> Self {
fn new() -> Self {
Input {
renderable : always,
weight : 0,
input_type : InputType::Textfield,
name : None,
value : None,
label : None,
name : OptionId::none(),
value : OptionAttr::none(),
label : OptionAttr::none(),
size : Some(60),
minlength : None,
maxlength : Some(128),
placeholder : None,
autofocus : None,
autocomplete: None,
disabled : None,
readonly : None,
required : None,
help_text : None,
placeholder : OptionAttr::none(),
autofocus : OptionAttr::none(),
autocomplete: OptionAttr::none(),
disabled : OptionAttr::none(),
readonly : OptionAttr::none(),
required : OptionAttr::none(),
help_text : OptionAttr::none(),
template : "default".to_owned(),
}
}
@ -63,7 +63,7 @@ impl PageComponent for Input {
InputType::Textfield => ("text", "form-type-textfield"),
InputType::Url => ("url", "form-type-url")
};
let (class_item, id_item) = match &self.name {
let (class_item, id_item) = match &self.name.option() {
Some(name) => (
format!("form-item form-item-{} {}", name, class_type),
Some(format!("edit-{}", name))
@ -75,10 +75,10 @@ impl PageComponent for Input {
};
html! {
div class=(class_item) {
@if self.label != None {
@if self.label.has_value() {
label class="form-label" for=[&id_item] {
(self.label()) " "
@if self.required != None {
(self.label.value()) " "
@if self.required.has_value() {
span
class="form-required"
title="Este campo es obligatorio."
@ -92,20 +92,20 @@ impl PageComponent for Input {
type=(input_type)
id=[&id_item]
class="form-control"
name=[&self.name]
value=[&self.value]
name=[&self.name.option()]
value=[&self.value.option()]
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];
@if self.help_text != None {
placeholder=[&self.placeholder.option()]
autofocus=[&self.autofocus.option()]
autocomplete=[&self.autocomplete.option()]
readonly=[&self.readonly.option()]
required=[&self.required.option()]
disabled=[&self.disabled.option()];
@if self.help_text.has_value() {
div class="form-text" {
(self.help_text())
(self.help_text.value())
}
}
}
@ -116,35 +116,35 @@ impl PageComponent for Input {
impl Input {
pub fn textfield() -> Self {
Input::prepare()
Input::new()
}
pub fn password() -> Self {
let mut input = Input::prepare();
let mut input = Input::new();
input.input_type = InputType::Password;
input
}
pub fn search() -> Self {
let mut input = Input::prepare();
let mut input = Input::new();
input.input_type = InputType::Search;
input
}
pub fn email() -> Self {
let mut input = Input::prepare();
let mut input = Input::new();
input.input_type = InputType::Email;
input
}
pub fn telephone() -> Self {
let mut input = Input::prepare();
let mut input = Input::new();
input.input_type = InputType::Telephone;
input
}
pub fn url() -> Self {
let mut input = Input::prepare();
let mut input = Input::new();
input.input_type = InputType::Url;
input
}
@ -162,17 +162,17 @@ impl Input {
}
pub fn with_name(mut self, name: &str) -> Self {
self.name = util::valid_id(name);
self.name.with_value(name);
self
}
pub fn with_value(mut self, value: &str) -> Self {
self.value = util::valid_str(value);
self.value.with_value(value);
self
}
pub fn with_label(mut self, label: &str) -> Self {
self.label = util::valid_str(label);
self.label.with_value(label);
self
}
@ -192,52 +192,52 @@ impl Input {
}
pub fn with_placeholder(mut self, placeholder: &str) -> Self {
self.placeholder = util::valid_str(placeholder);
self.placeholder.with_value(placeholder);
self
}
pub fn autofocus(mut self, toggle: bool) -> Self {
self.autofocus = match toggle {
true => Some("autofocus".to_owned()),
false => None
};
self.autofocus.with_value(match toggle {
true => "autofocus",
false => "",
});
self
}
pub fn autocomplete(mut self, toggle: bool) -> Self {
self.autocomplete = match toggle {
true => None,
false => Some("off".to_owned())
};
self.autocomplete.with_value(match toggle {
true => "",
false => "off",
});
self
}
pub fn disabled(mut self, toggle: bool) -> Self {
self.disabled = match toggle {
true => Some("disabled".to_owned()),
false => None
};
self.disabled.with_value(match toggle {
true => "disabled",
false => "",
});
self
}
pub fn readonly(mut self, toggle: bool) -> Self {
self.readonly = match toggle {
true => Some("readonly".to_owned()),
false => None
};
self.readonly.with_value(match toggle {
true => "readonly",
false => "",
});
self
}
pub fn required(mut self, toggle: bool) -> Self {
self.required = match toggle {
true => Some("required".to_owned()),
false => None
};
self.required.with_value(match toggle {
true => "required",
false => "",
});
self
}
pub fn with_help_text(mut self, help_text: &str) -> Self {
self.help_text = util::valid_str(help_text);
self.help_text.with_value(help_text);
self
}
@ -249,15 +249,15 @@ impl Input {
// Input GETTERS.
pub fn name(&self) -> &str {
util::assigned_str(&self.name)
self.name.value()
}
pub fn value(&self) -> &str {
util::assigned_str(&self.value)
self.value.value()
}
pub fn label(&self) -> &str {
util::assigned_str(&self.label)
self.label.value()
}
pub fn size(&self) -> Option<u16> {
@ -273,46 +273,31 @@ impl Input {
}
pub fn placeholder(&self) -> &str {
util::assigned_str(&self.placeholder)
self.placeholder.value()
}
pub fn has_autofocus(&self) -> bool {
match &self.autofocus {
Some(_) => true,
_ => false
}
self.autofocus.has_value()
}
pub fn has_autocomplete(&self) -> bool {
match &self.autocomplete {
Some(_) => false,
_ => true
}
!self.autocomplete.has_value()
}
pub fn is_disabled(&self) -> bool {
match &self.disabled {
Some(_) => true,
_ => false
}
self.disabled.has_value()
}
pub fn is_readonly(&self) -> bool {
match &self.readonly {
Some(_) => true,
_ => false
}
self.readonly.has_value()
}
pub fn is_required(&self) -> bool {
match &self.required {
Some(_) => true,
_ => false
}
self.required.has_value()
}
pub fn help_text(&self) -> &str {
util::assigned_str(&self.help_text)
self.help_text.value()
}
pub fn template(&self) -> &str {

View file

@ -0,0 +1,82 @@
use crate::prelude::*;
pub struct Column {
renderable: fn() -> bool,
weight : i8,
id : OptionId,
components: PageContainer,
template : String,
}
impl PageComponent for Column {
fn new() -> Self {
Column {
renderable: always,
weight : 0,
id : OptionId::none(),
components: PageContainer::new(),
template : "default".to_owned(),
}
}
fn is_renderable(&self) -> bool {
(self.renderable)()
}
fn weight(&self) -> i8 {
self.weight
}
fn default_render(&self, assets: &mut PageAssets) -> Markup {
html! {
div id=[&self.id.option()] class="col" {
(self.components.render(assets))
}
}
}
}
impl Column {
// Column BUILDER.
pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self {
self.renderable = renderable;
self
}
pub fn with_weight(mut self, weight: i8) -> Self {
self.weight = weight;
self
}
pub fn with_id(mut self, id: &str) -> Self {
self.id.with_value(id);
self
}
pub fn add(mut self, component: impl PageComponent) -> Self {
self.components.add(component);
self
}
pub fn using_template(mut self, template: &str) -> Self {
self.template = template.to_owned();
self
}
// Column GETTERS.
pub fn id(&self) -> &str {
self.id.value()
}
pub fn template(&self) -> &str {
self.template.as_str()
}
}
fn always() -> bool {
true
}

View file

@ -0,0 +1,4 @@
mod row;
pub use row::Row;
mod column;
pub use column::Column;

View file

@ -0,0 +1,82 @@
use crate::prelude::*;
pub struct Row {
renderable: fn() -> bool,
weight : i8,
id : OptionId,
columns : PageContainer,
template : String,
}
impl PageComponent for Row {
fn new() -> Self {
Row {
renderable: always,
weight : 0,
id : OptionId::none(),
columns : PageContainer::new(),
template : "default".to_owned(),
}
}
fn is_renderable(&self) -> bool {
(self.renderable)()
}
fn weight(&self) -> i8 {
self.weight
}
fn default_render(&self, assets: &mut PageAssets) -> Markup {
html! {
div id=[&self.id.option()] class="row" {
(self.columns.render(assets))
}
}
}
}
impl Row {
// Row BUILDER.
pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self {
self.renderable = renderable;
self
}
pub fn with_weight(mut self, weight: i8) -> Self {
self.weight = weight;
self
}
pub fn with_id(mut self, id: &str) -> Self {
self.id.with_value(id);
self
}
pub fn add_column(mut self, column: grid::Column) -> Self {
self.columns.add(column);
self
}
pub fn using_template(mut self, template: &str) -> Self {
self.template = template.to_owned();
self
}
// Row GETTERS.
pub fn id(&self) -> &str {
self.id.value()
}
pub fn template(&self) -> &str {
self.template.as_str()
}
}
fn always() -> bool {
true
}

View file

@ -0,0 +1,70 @@
use crate::prelude::*;
pub struct Image {
renderable: fn() -> bool,
weight : i8,
source : Option<String>,
template : String,
}
impl PageComponent for Image {
fn new() -> Self {
Image {
renderable: always,
weight : 0,
source : None,
template : "default".to_owned(),
}
}
fn is_renderable(&self) -> bool {
(self.renderable)()
}
fn weight(&self) -> i8 {
self.weight
}
fn default_render(&self, _: &mut PageAssets) -> Markup {
html! {
img src=[&self.source] class="img-fluid" {}
}
}
}
impl Image {
pub fn image(source: &str) -> Self {
let mut i = Image::new();
i.source = Some(source.to_owned());
i
}
// Image BUILDER.
pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self {
self.renderable = renderable;
self
}
pub fn with_weight(mut self, weight: i8) -> Self {
self.weight = weight;
self
}
pub fn using_template(mut self, template: &str) -> Self {
self.template = template.to_owned();
self
}
// Image GETTERS.
pub fn template(&self) -> &str {
self.template.as_str()
}
}
fn always() -> bool {
true
}

View file

@ -4,7 +4,7 @@ enum MenuItemType {
Label(String),
Link(String, String),
LinkBlank(String, String),
Markup(Markup),
Html(Markup),
Separator,
Submenu(String, Menu),
}
@ -21,7 +21,7 @@ pub struct MenuItem {
impl PageComponent for MenuItem {
fn prepare() -> Self {
fn new() -> Self {
MenuItem {
renderable: always,
weight : 0,
@ -50,8 +50,8 @@ impl PageComponent for MenuItem {
a href=(path) target="_blank" { (label) }
}
},
Some(MenuItemType::Markup(markup)) => html! {
li class="markup" { (*markup) }
Some(MenuItemType::Html(html)) => html! {
li class="html" { (*html) }
},
Some(MenuItemType::Submenu(label, menu)) => html! {
li class="submenu" {
@ -101,11 +101,11 @@ impl MenuItem {
}
}
pub fn markup(markup: Markup) -> Self {
pub fn html(html: Markup) -> Self {
MenuItem {
renderable: always,
weight : 0,
item_type : Some(MenuItemType::Markup(markup)),
item_type : Some(MenuItemType::Html(html)),
}
}
@ -148,18 +148,18 @@ impl MenuItem {
pub struct Menu {
renderable: fn() -> bool,
weight : i8,
id : Option<String>,
id : OptionId,
items : PageContainer,
template : String,
}
impl PageComponent for Menu {
fn prepare() -> Self {
fn new() -> Self {
Menu {
renderable: always,
weight : 0,
id : None,
id : OptionId::none(),
items : PageContainer::new(),
template : "default".to_owned(),
}
@ -186,7 +186,7 @@ impl PageComponent for Menu {
))
.add_jquery();
let id = assets.serial_id(self.name(), self.id());
let id = assets.serial_id(self.name(), self.id.value());
html! {
ul id=(id) class="sm sm-clean" {
(self.render_items(assets))
@ -216,7 +216,7 @@ impl Menu {
}
pub fn with_id(mut self, id: &str) -> Self {
self.id = util::valid_id(id);
self.id.with_value(id);
self
}
@ -233,7 +233,7 @@ impl Menu {
// Menu GETTERS.
pub fn id(&self) -> &str {
util::assigned_str(&self.id)
self.id.value()
}
pub fn template(&self) -> &str {

View file

@ -1,9 +1,14 @@
mod container;
pub use container::Container;
pub mod grid;
mod chunck;
pub use chunck::Chunck;
mod block;
pub use block::Block;
mod image;
pub use image::Image;
mod menu;
pub use menu::{Menu, MenuItem};

View file

@ -3,19 +3,23 @@ module_description = Displays a demo homepage when none is configured.
page_title = Hello world!
text_welcome = This page is used to test the proper operation of { $app } after installation. This web solution is powered by { $pagetop }. If you can read this page, it means that the PageTop server is working properly, but has not yet been configured.
welcome_to = Welcome to { $app }
welcome_intro = This page is used to test the proper operation of { $app } after installation.
welcome_pagetop = This web solution is powered by { $pagetop }.
title_normal_user = Just visiting?
text1_normal_user = If you are a normal user of this web site and don't know what this page is about, this probably means that the site is either experiencing problems or is undergoing routine maintenance.
text2_normal_user = If the problem persists, please contact your system administrator.
visiting_title = Just visiting?
visiting_subtitle = Are you user of this website?
visiting_text1 = If you don't know what this page is about, this probably means that the site is either experiencing problems or is undergoing routine maintenance.
visiting_text2 = If the problem persists, please contact your system administrator.
title_about_pagetop = About PageTop
text1_about_pagetop = PageTop defines an interface for the most stable and popular Rust packages to build modular, extensible and configurable web solutions.
text2_about_pagetop = For information on PageTop please visit the "PageTop website".
pagetop_title = About PageTop
pagetop_text1 = If you can read this page, it means that the PageTop server is working properly, but has not yet been configured.
pagetop_text2 = PageTop defines an interface for the most stable and popular Rust packages to build modular, extensible and configurable web solutions.
pagetop_text3 = For information on PageTop please visit the "PageTop website".
title_promo_pagetop = Promoting PageTop
text1_promo_pagetop = You are free to use the image below on applications powered by { $pagetop }. Thanks for using PageTop!
pagetop_promo_title = Promoting PageTop
pagetop_promo_text1 = You are free to use the image below on applications powered by { $pagetop }. Thanks for using PageTop!
title_report_problems = Reporting Problems
text1_report_problems = Please use the GitLab tool to report bugs in PageTop. However, check "existing bug reports" before reporting a new bug.
text2_report_problems = Please report bugs specific to modules (such as admin, and others) to respective packages, not to PageTop itself.
report_problems_title = Reporting Problems
report_problems_text1 = Please use the GitLab tool to report bugs in PageTop. However, check "existing bug reports" before reporting a new bug.
report_problems_text2 = Please report bugs specific to modules (such as admin, and others) to respective packages, not to PageTop itself.

View file

@ -3,19 +3,23 @@ module_description = Muestra una página de demostración predeterminada cuando
page_title = ¡Hola mundo!
text_welcome = Esta página se utiliza para probar el correcto funcionamiento de { $app } después de la instalación. Esta solución web funciona con { $pagetop }. Si puede leer esta página, significa que el servidor PageTop funciona correctamente, pero aún no se ha configurado.
welcome_to = Bienvenido a { $app }
welcome_intro = Esta página se utiliza para probar el correcto funcionamiento de { $app } después de la instalación.
welcome_pagetop = Esta solución web funciona con { $pagetop }.
title_normal_user = ¿Sólo de visita?
text1_normal_user = Si usted es un usuario normal de este sitio web y no sabe de qué trata esta página, probablemente significa que el sitio está experimentando problemas o está pasando por un mantenimiento de rutina.
text2_normal_user = Si el problema persiste, póngase en contacto con el administrador del sistema.
visiting_title = ¿Sólo de visita?
visiting_subtitle = ¿Eres usuario de este sitio web?
visiting_text1 = Si no sabes de qué trata esta página, probablemente significa que el sitio está experimentando problemas o está pasando por un mantenimiento de rutina.
visiting_text2 = Si el problema persiste, póngase en contacto con el administrador del sistema.
title_about_pagetop = Sobre PageTop
text1_about_pagetop = PageTop define una interfaz para los paquetes Rust más estables y populares para crear soluciones web modulares, extensibles y configurables.
text2_about_pagetop = Para obtener información sobre PageTop, visite el "sitio web de PageTop".
pagetop_title = Sobre PageTop
pagetop_text1 = Si puedes leer esta página, significa que el servidor PageTop funciona correctamente, pero aún no se ha configurado.
pagetop_text2 = PageTop define una interfaz para los paquetes Rust más estables y populares para crear soluciones web modulares, extensibles y configurables.
pagetop_text3 = Para obtener información sobre PageTop, visita el "sitio web de PageTop".
title_promo_pagetop = Promociona PageTop
text1_promo_pagetop = Puede usar la siguiente imagen en aplicaciones desarrolladas sobre { $pagetop }. ¡Gracias por usar PageTop!
pagetop_promo_title = Promociona PageTop
pagetop_promo_text1 = Puedes usar la siguiente imagen en aplicaciones desarrolladas sobre { $pagetop }. ¡Gracias por usar PageTop!
title_report_problems = Informando Problemas
text1_report_problems = Utilice la herramienta GitLab para informar errores en PageTop. Sin embargo, verifique los "informes de errores existentes" antes de informar de un nuevo error.
text2_report_problems = Informe los errores específicos de los módulos (como admin y otros) a los paquetes respectivos, no a PageTop en sí.
report_problems_title = Informando Problemas
report_problems_text1 = Utilice la herramienta GitLab para informar errores en PageTop. Sin embargo, verifique los "informes de errores existentes" antes de informar de un nuevo error.
report_problems_text2 = Informe los errores específicos de los módulos (como admin y otros) a los paquetes respectivos, no a PageTop en sí.

View file

@ -18,61 +18,210 @@ impl ModuleTrait for DemopageModule {
}
fn configure_module(&self, cfg: &mut app::web::ServiceConfig) {
cfg.route("/", app::web::get().to(home));
cfg.route("/", app::web::get().to(demo));
}
}
async fn home() -> app::Result<Markup> {
Page::prepare()
async fn demo() -> app::Result<Markup> {
Page::new()
.using_theme("Bootsier")
.with_title(
l("page_title").as_str()
)
.add_to("content", Container::prepare()
.with_id("welcome")
.add(Chunck::markup(html! {
h1 { (l("page_title")) }
p { (e("text_welcome", &args![
"app" => format!("<strong>{}</strong>", &SETTINGS.app.name),
"pagetop" => "<a href=\"https://pagetop-rs\">PageTop</a>"
])) }
}))
)
.add_to("content", Container::prepare()
.add(Container::row()
.add(Container::column()
.with_id("visitors")
.add(Chunck::markup(html! {
h2 { (l("title_normal_user")) }
p { (l("text1_normal_user")) }
p { (l("text2_normal_user")) }
})))
.add(Container::column()
.with_id("pagetop")
.add(Chunck::markup(html! {
h2 { (l("title_about_pagetop")) }
p { (l("text1_about_pagetop")) }
p { (l("text2_about_pagetop")) }
h2 { (l("title_promo_pagetop")) }
p { (e("text1_promo_pagetop", &args![
"pagetop" =>
"<a href=\"https://pagetop-rs\">PageTop</a>"
])) }
}))
)
)
)
.add_to("content", Container::prepare()
.with_id("reporting")
.add(Chunck::markup(html! {
h2 { (l("title_report_problems")) }
p { (l("text1_report_problems")) }
p { (l("text2_report_problems")) }
}))
)
.with_title(l("page_title").as_str())
.add_to("content", hello_world())
.add_to("content", hello_world2())
.add_to("content", just_visiting())
.add_to("content", about_pagetop())
.add_to("content", promo_pagetop())
.add_to("content", reporting_problems())
.render()
}
fn hello_world2() -> Container {
Container::header()
.add(grid::Row::new()
.add_column(grid::Column::new()
.add(Chunck::with(html! {
div class="section-title" {
(t("welcome_to", &args![
"app" => SETTINGS.app.name.as_str()
]))
}
h1 class="h1-large" {
(l("page_title"))
}
p class="p-large" {
(e("welcome_intro", &args![
"app" => format!(
"<strong>{}</strong>",
&SETTINGS.app.name
)
]))
}
p {
(e("welcome_pagetop", &args![
"pagetop" => "<a href=\"https://pagetop-rs\">PageTop</a>"
]))
}
a class="btn-solid-lg" href="#services" {
"Offered services"
}
a class="quote" href="#contact" {
i class="fas fa-paper-plane" {}
"Get quote"
}
}))
)
.add_column(grid::Column::new()
.add(Image::image("/bootsier/images/demo-header.svg"))
)
)
}
fn hello_world() -> Chunck {
Chunck::with(html! {
header id="header" class="header" {
div class="container" {
div class="row" {
div class="col-lg-6 col-xl-5" {
div class="text-container" {
div class="section-title" {
(t("welcome_to", &args![
"app" => SETTINGS.app.name.as_str()
]))
}
h1 class="h1-large" {
(l("page_title"))
}
p class="p-large" {
(e("welcome_intro", &args![
"app" => format!(
"<strong>{}</strong>",
&SETTINGS.app.name
)
]))
}
p {
(e("welcome_pagetop", &args![
"pagetop" => "<a href=\"https://pagetop-rs\">PageTop</a>"
]))
}
a class="btn-solid-lg" href="#services" {
"Offered services"
}
a class="quote" href="#contact" {
i class="fas fa-paper-plane" {}
"Get quote"
}
}
}
div class="col-lg-6 col-xl-7" {
div class="image-container" {
img class="img-fluid" src="/bootsier/images/demo-header.svg" alt="alternative" {}
}
}
}
}
}
})
}
fn just_visiting() -> Chunck {
Chunck::with(html! {
div id="details" class="basic-1" {
div class="container" {
div class="row" {
div class="col-lg-6 col-xl-7" {
div class="image-container" {
img class="img-fluid" src="/bootsier/images/demo-visiting.svg" alt="alternative" {}
}
}
div class="col-lg-6 col-xl-5" {
div class="text-container" {
h2 {
span {
(l("visiting_title"))
}
br {}
(l("visiting_subtitle"))
}
p { (l("visiting_text1")) }
p { (l("visiting_text2")) }
a class="btn-solid-reg" data-bs-toggle="modal" data-bs-target="#staticBackdrop" { "Modal" }
}
}
}
}
}
})
}
fn about_pagetop() -> Chunck {
Chunck::with(html! {
div id="pagetop" class="basic-2" {
div class="container" {
div class="row" {
div class="col-lg-6 col-xl-5" {
div class="text-container" {
h2 { (l("pagetop_title")) }
p { (l("pagetop_text1")) }
p { (l("pagetop_text2")) }
p { (l("pagetop_text3")) }
}
}
div class="col-lg-6 col-xl-7" {
div class="image-container" {
img class="img-fluid" src="/bootsier/images/demo-pagetop.svg" alt="alternative" {}
}
}
}
}
}
})
}
fn promo_pagetop() -> Chunck {
Chunck::with(html! {
div id="promo" class="basic-3" {
div class="container" {
div class="row" {
div class="col-lg-6 col-xl-5" {
div class="text-container" {
h2 { (l("pagetop_promo_title")) }
p { (e("pagetop_promo_text1", &args![
"pagetop" =>
"<a href=\"https://pagetop-rs\">PageTop</a>"
])) }
}
}
div class="col-lg-6 col-xl-7" {
div class="image-container" {
img class="img-fluid" src="/bootsier/images/demo-pagetop.svg" alt="alternative" {}
}
}
}
}
}
})
}
fn reporting_problems() -> Chunck {
Chunck::with(html! {
div id="reporting" class="basic-4" {
div class="container" {
div class="row" {
div class="col-lg-6 col-xl-5" {
div class="text-container" {
h2 { (l("report_problems_title")) }
p { (l("report_problems_text1")) }
p { (l("report_problems_text2")) }
}
}
div class="col-lg-6 col-xl-7" {
div class="image-container" {
img class="img-fluid" src="/bootsier/images/demo-pagetop.svg" alt="alternative" {}
}
}
}
}
}
})
}

View file

@ -52,9 +52,9 @@ impl ThemeTrait for BootsierTheme {
s = app::http::StatusCode::INTERNAL_SERVER_ERROR;
}
}
Page::prepare()
Page::new()
.with_title(format!("Error {}", s.as_str()).as_str())
.add_to("content", Chunck::markup(html! {
.add_to("content", Chunck::with(html! {
div class="jumbotron" {
div class="media" {
img

View file

@ -1 +0,0 @@
pub use maud::{DOCTYPE, Markup, PreEscaped, html};

View file

@ -0,0 +1,63 @@
pub struct Classes {
classes: Vec<String>,
option : Option<String>,
updated: bool,
}
impl Classes {
pub fn none() -> Self {
Classes {
classes: Vec::new(),
option : None,
updated: true,
}
}
pub fn some_class(class: &str) -> Self {
let mut c = Classes::none();
c.add_class(class);
c
}
pub fn some_classes(classes: Vec<String>) -> Self {
let mut c = Classes::none();
c.add_classes(classes);
c
}
pub fn add_class(&mut self, class: &str) {
let class = class.trim().replace(" ", "_");
if !class.is_empty() && !self.classes.iter().any(|c| *c == class) {
self.classes.push(class.to_owned());
self.updated = false;
}
}
pub fn add_classes(&mut self, classes: Vec<String>) {
for class in classes.iter() {
self.add_class(class);
}
}
pub fn classes(&mut self) -> &str {
match self.option() {
Some(classes) => classes.as_str(),
None => "",
}
}
pub fn has_classes(&self) -> bool {
self.classes.len() > 0
}
pub fn option(&mut self) -> &Option<String> {
if !self.updated {
self.option = match self.classes.len() {
0 => None,
_ => Some(self.classes.join(" ")),
};
self.updated = true;
}
&self.option
}
}

8
pagetop/src/html/mod.rs Normal file
View file

@ -0,0 +1,8 @@
pub use maud::{DOCTYPE, Markup, PreEscaped, html};
mod optional_id;
pub use optional_id::OptionId;
mod optional_attr;
pub use optional_attr::OptionAttr;
mod classes;
pub use classes::Classes;

View file

@ -0,0 +1,41 @@
pub struct OptionAttr(Option<String>);
impl OptionAttr {
pub fn none() -> Self {
OptionAttr(None)
}
pub fn some(value: &str) -> Self {
let value = value.trim();
match value.is_empty() {
true => OptionAttr(None),
false => OptionAttr(Some(value.to_owned())),
}
}
pub fn with_value(&mut self, value: &str) {
let value = value.trim();
self.0 = match value.is_empty() {
true => None,
false => Some(value.to_owned()),
};
}
pub fn value(&self) -> &str {
match &self.0 {
Some(value) => value.as_str(),
None => "",
}
}
pub fn has_value(&self) -> bool {
match &self.0 {
Some(_) => true,
None => false,
}
}
pub fn option(&self) -> &Option<String> {
&self.0
}
}

View file

@ -0,0 +1,33 @@
pub struct OptionId(Option<String>);
impl OptionId {
pub fn none() -> Self {
OptionId(None)
}
pub fn with_value(&mut self, id: &str) {
let id = id.trim();
self.0 = match id.is_empty() {
true => None,
false => Some(id.replace(" ", "_")),
};
}
pub fn value(&self) -> &str {
match &self.0 {
Some(id) => id.as_str(),
None => "",
}
}
pub fn has_value(&self) -> bool {
match &self.0 {
Some(_) => true,
None => false,
}
}
pub fn option(&self) -> &Option<String> {
&self.0
}
}

View file

@ -7,7 +7,7 @@ use std::any::type_name;
pub trait PageComponent: Downcast + Send + Sync {
fn prepare() -> Self where Self: Sized;
fn new() -> Self where Self: Sized;
fn name(&self) -> &'static str {
let name = type_name::<Self>();

View file

@ -1,9 +1,8 @@
use crate::{Lazy, app, trace, util};
use crate::{Lazy, app, trace};
use crate::config::SETTINGS;
use crate::html::{DOCTYPE, Markup, html};
use crate::html::{Classes, DOCTYPE, Markup, OptionAttr, html};
use crate::response::page::{PageAssets, PageComponent, PageContainer};
use std::borrow::Cow;
use std::sync::RwLock;
use std::collections::HashMap;
@ -41,31 +40,31 @@ static DEFAULT_DIRECTION: Lazy<Option<String>> = Lazy::new(|| {
pub enum TextDirection { Auto, LeftToRight, RightToLeft }
pub struct Page<'a> {
language : Option<String>,
direction : Option<String>,
title : Option<String>,
description : Option<String>,
language : OptionAttr,
direction : OptionAttr,
title : OptionAttr,
description : OptionAttr,
assets : PageAssets,
body_classes: Cow<'a, str>,
body_classes: Classes,
regions : HashMap<&'a str, PageContainer>,
template : String,
}
impl<'a> Page<'a> {
pub fn prepare() -> Self {
pub fn new() -> Self {
Page {
language : match &*DEFAULT_LANGUAGE {
Some(language) => Some(language.to_owned()),
_ => None,
Some(language) => OptionAttr::some(language),
_ => OptionAttr::none(),
},
direction : match &*DEFAULT_DIRECTION {
Some(direction) => Some(direction.to_owned()),
_ => None,
Some(direction) => OptionAttr::some(direction),
_ => OptionAttr::none(),
},
title : None,
description : None,
body_classes: "body".into(),
title : OptionAttr::none(),
description : OptionAttr::none(),
body_classes: Classes::some_class("body"),
assets : PageAssets::new(),
regions : COMPONENTS.read().unwrap().clone(),
template : "default".to_owned(),
@ -75,38 +74,36 @@ impl<'a> Page<'a> {
// Page BUILDER.
pub fn with_language(&mut self, language: &str) -> &mut Self {
self.language = util::valid_str(language);
self.language.with_value(language);
self
}
pub fn with_direction(&mut self, dir: TextDirection) -> &mut Self {
self.direction = match dir {
TextDirection::Auto => Some("auto".to_owned()),
TextDirection::LeftToRight => Some("ltr".to_owned()),
TextDirection::RightToLeft => Some("rtl".to_owned()),
};
self.direction.with_value(match dir {
TextDirection::Auto => "auto",
TextDirection::LeftToRight => "ltr",
TextDirection::RightToLeft => "rtl",
});
self
}
pub fn with_title(&mut self, title: &str) -> &mut Self {
self.title = util::valid_str(title);
self.title.with_value(title);
self
}
pub fn with_description(&mut self, description: &str) -> &mut Self {
self.description = util::valid_str(description);
self.description.with_value(description);
self
}
pub fn with_body_classes(&mut self, body_classes: &'a str) -> &mut Self {
self.body_classes = body_classes.into();
pub fn add_body_class(&mut self, class: &str) -> &mut Self {
self.body_classes.add_class(class);
self
}
pub fn add_body_classes(&mut self, body_classes: &'a str) -> &mut Self {
self.body_classes = String::from(
format!("{} {}", self.body_classes, body_classes).trim()
).into();
pub fn add_body_classes(&mut self, classes: Vec<String>) -> &mut Self {
self.body_classes.add_classes(classes);
self
}
@ -131,26 +128,23 @@ impl<'a> Page<'a> {
// Page GETTERS.
pub fn language(&self) -> &str {
util::assigned_str(&self.language)
self.language.value()
}
pub fn direction(&self) -> &str {
util::assigned_str(&self.direction)
self.direction.value()
}
pub fn title(&self) -> &str {
util::assigned_str(&self.title)
self.title.value()
}
pub fn description(&self) -> &str {
util::assigned_str(&self.description)
self.description.value()
}
pub fn body_classes(&self) -> &str {
if self.body_classes.is_empty() {
return "body";
}
&self.body_classes
pub fn body_classes(&mut self) -> &str {
self.body_classes.classes()
}
pub fn assets(&mut self) -> &mut PageAssets {
@ -176,7 +170,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.option()] dir=[&self.direction.option()] {
(head)
(body)
}
@ -204,7 +198,7 @@ pub fn render_component(
) -> Markup {
match component.is_renderable() {
true => match assets.theme().render_component(component, assets) {
Some(markup) => markup,
Some(html) => html,
None => component.default_render(assets)
},
false => html! {}

View file

@ -99,9 +99,9 @@ pub trait ThemeTrait: Send + Sync {
}
fn render_error_page(&self, s: app::http::StatusCode) -> app::Result<Markup> {
Page::prepare()
Page::new()
.with_title(format!("Error {}", s.as_str()).as_str())
.add_to("content", Chunck::markup(html! {
.add_to("content", Chunck::with(html! {
div {
h1 { (s) }
}

View file

@ -35,26 +35,3 @@ macro_rules! theme_static_files {
}
}};
}
pub fn valid_id(id: &str) -> Option<String> {
let id = id.trim();
match id.is_empty() {
true => None,
false => Some(id.replace(" ", "_").to_lowercase()),
}
}
pub fn valid_str(s: &str) -> Option<String> {
let s = s.trim();
match s.is_empty() {
true => None,
false => Some(s.to_owned()),
}
}
pub fn assigned_str(optional: &Option<String>) -> &str {
match optional {
Some(o) => o.as_str(),
None => "",
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 52 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 33 KiB