Modifica la estructura general del código fuente

Importante actualización que reorganiza el código fuente de PageTop. Usa
Cargo para crear un espacio de trabajo con los diferentes proyectos que
estructuran las funcionalidades de PageTop en módulos interdependientes
que se integran en Drust para construir una solución web para la gestión
de contenidos.
This commit is contained in:
Manuel Cillero 2022-03-13 11:14:33 +01:00
parent 4b5d8ce38a
commit ab0ac11f65
83 changed files with 115 additions and 81 deletions

View file

@ -1,105 +0,0 @@
use crate::prelude::*;
pub struct Block {
renderable: fn() -> bool,
weight : i8,
id : Option<String>,
title : Option<String>,
markup : Vec<Markup>,
template : String,
}
impl PageComponent for Block {
fn prepare() -> Self {
Block {
renderable: always,
weight : 0,
id : None,
title : None,
markup : Vec::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 {
let id = assets.serial_id(self.name(), self.id());
html! {
div id=(id) class="block" {
@if self.title != None {
h2 class="block-title" { (self.title()) }
}
div class="block-body" {
@for markup in self.markup.iter() {
(*markup)
}
}
}
}
}
}
impl Block {
pub fn markup(markup: Markup) -> Self {
Block::prepare().add_markup(markup)
}
// Block 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 = util::valid_id(id);
self
}
pub fn with_title(mut self, title: &str) -> Self {
self.title = util::optional_str(title);
self
}
pub fn add_markup(mut self, markup: Markup) -> Self {
self.markup.push(markup);
self
}
pub fn using_template(mut self, template: &str) -> Self {
self.template = template.to_owned();
self
}
// Block GETTERS.
pub fn id(&self) -> &str {
util::assigned_str(&self.id)
}
pub fn title(&self) -> &str {
util::assigned_str(&self.title)
}
pub fn template(&self) -> &str {
self.template.as_str()
}
}
fn always() -> bool {
true
}

View file

@ -1,75 +0,0 @@
use crate::prelude::*;
pub struct Chunck {
renderable: fn() -> bool,
weight : i8,
markup : Vec<Markup>,
template : String,
}
impl PageComponent for Chunck {
fn prepare() -> Self {
Chunck {
renderable: always,
weight : 0,
markup : Vec::new(),
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! {
@for markup in self.markup.iter() {
(*markup)
}
}
}
}
impl Chunck {
pub fn markup(markup: Markup) -> Self {
Chunck::prepare().add_markup(markup)
}
// Chunck 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 add_markup(mut self, markup: Markup) -> Self {
self.markup.push(markup);
self
}
pub fn using_template(mut self, template: &str) -> Self {
self.template = template.to_owned();
self
}
// Chunck GETTERS.
pub fn template(&self) -> &str {
self.template.as_str()
}
}
fn always() -> bool {
true
}

View file

@ -1,103 +0,0 @@
use crate::prelude::*;
enum ContainerType { Column, Row, Wrapper }
pub struct Container {
renderable: fn() -> bool,
weight : i8,
id : Option<String>,
container : ContainerType,
components: PageContainer,
template : String,
}
impl PageComponent for Container {
fn prepare() -> Self {
Container {
renderable: always,
weight : 0,
id : None,
container : ContainerType::Wrapper,
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 {
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))
}
}
}
}
impl Container {
pub fn row() -> Self {
let mut grid = Container::prepare();
grid.container = ContainerType::Row;
grid
}
pub fn column() -> Self {
let mut grid = Container::prepare();
grid.container = ContainerType::Column;
grid
}
// Container 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 = util::valid_id(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
}
// Container GETTERS.
pub fn id(&self) -> &str {
util::assigned_str(&self.id)
}
pub fn template(&self) -> &str {
self.template.as_str()
}
}
fn always() -> bool {
true
}

View file

@ -1,160 +0,0 @@
use crate::prelude::*;
enum ButtonType {Button, Reset, Submit}
pub struct Button {
renderable : fn() -> bool,
weight : i8,
button_type: ButtonType,
name : Option<String>,
value : Option<String>,
autofocus : Option<String>,
disabled : Option<String>,
template : String,
}
impl PageComponent for Button {
fn prepare() -> Self {
Button {
renderable : always,
weight : 0,
button_type: ButtonType::Button,
name : None,
value : None,
autofocus : None,
disabled : 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 {
let (button_type, button_class) = match &self.button_type {
ButtonType::Button => ("button", "btn btn-primary form-button"),
ButtonType::Reset => ("reset", "btn btn-primary form-reset" ),
ButtonType::Submit => ("submit", "btn btn-primary form-submit")
};
let id_item = match &self.name {
Some(name) => Some(format!("edit-{}", name)),
_ => None
};
html! {
button
type=(button_type)
id=[&id_item]
class=(button_class)
name=[&self.name]
value=[&self.value]
autofocus=[&self.autofocus]
disabled=[&self.disabled]
{
@match &self.value {
Some(value) => (value),
_ => ""
};
}
}
}
}
impl Button {
pub fn button(value: &str) -> Self {
Button::prepare().with_value(value)
}
pub fn reset(value: &str) -> Self {
let mut button = Button::prepare().with_value(value);
button.button_type = ButtonType::Reset;
button
}
pub fn submit(value: &str) -> Self {
let mut button = Button::prepare().with_value(value);
button.button_type = ButtonType::Submit;
button
}
// Button 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_name(mut self, name: &str) -> Self {
self.name = util::valid_id(name);
self
}
pub fn with_value(mut self, value: &str) -> Self {
self.value = util::optional_str(value);
self
}
pub fn autofocus(mut self, toggle: bool) -> Self {
self.autofocus = match toggle {
true => Some("autofocus".to_owned()),
false => None
};
self
}
pub fn disabled(mut self, toggle: bool) -> Self {
self.disabled = match toggle {
true => Some("disabled".to_owned()),
false => None
};
self
}
pub fn using_template(mut self, template: &str) -> Self {
self.template = template.to_owned();
self
}
// Button GETTERS.
pub fn name(&self) -> &str {
util::assigned_str(&self.name)
}
pub fn value(&self) -> &str {
util::assigned_str(&self.value)
}
pub fn has_autofocus(&self) -> bool {
match &self.autofocus {
Some(_) => true,
_ => false
}
}
pub fn is_disabled(&self) -> bool {
match &self.disabled {
Some(_) => true,
_ => false
}
}
pub fn template(&self) -> &str {
self.template.as_str()
}
}
fn always() -> bool {
true
}

View file

@ -1,243 +0,0 @@
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>,
template : String,
}
impl PageComponent for Date {
fn prepare() -> 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,
template : "default".to_owned(),
}
}
fn is_renderable(&self) -> bool {
(self.renderable)()
}
fn weight(&self) -> i8 {
self.weight
}
fn default_render(&self, _: &mut PageAssets) -> Markup {
let (class_item, id_item) = match &self.name {
Some(name) => (
format!("form-item form-item-{} form-type-date", name),
Some(format!("edit-{}", name))
),
None => (
"form-item form-type-date".to_owned(),
None
)
};
html! {
div class=(class_item) {
@if self.label != None {
label class="form-label" for=[&id_item] {
(self.label()) " "
@if self.required != None {
span
class="form-required"
title="Este campo es obligatorio."
{
"*"
} " "
}
}
}
input
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 {
div class="form-text" {
(self.help_text())
}
}
}
}
}
}
impl Date {
// Date 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_name(mut self, name: &str) -> Self {
self.name = util::valid_id(name);
self
}
pub fn with_value(mut self, value: &str) -> Self {
self.value = util::optional_str(value);
self
}
pub fn with_label(mut self, label: &str) -> Self {
self.label = util::optional_str(label);
self
}
pub fn with_placeholder(mut self, placeholder: &str) -> Self {
self.placeholder = util::optional_str(placeholder);
self
}
pub fn autofocus(mut self, toggle: bool) -> Self {
self.autofocus = match toggle {
true => Some("autofocus".to_owned()),
false => None
};
self
}
pub fn autocomplete(mut self, toggle: bool) -> Self {
self.autocomplete = match toggle {
true => None,
false => Some("off".to_owned())
};
self
}
pub fn disabled(mut self, toggle: bool) -> Self {
self.disabled = match toggle {
true => Some("disabled".to_owned()),
false => None
};
self
}
pub fn readonly(mut self, toggle: bool) -> Self {
self.readonly = match toggle {
true => Some("readonly".to_owned()),
false => None
};
self
}
pub fn required(mut self, toggle: bool) -> Self {
self.required = match toggle {
true => Some("required".to_owned()),
false => None
};
self
}
pub fn with_help_text(mut self, help_text: &str) -> Self {
self.help_text = util::optional_str(help_text);
self
}
pub fn using_template(mut self, template: &str) -> Self {
self.template = template.to_owned();
self
}
// Date GETTERS.
pub fn name(&self) -> &str {
util::assigned_str(&self.name)
}
pub fn value(&self) -> &str {
util::assigned_str(&self.value)
}
pub fn label(&self) -> &str {
util::assigned_str(&self.label)
}
pub fn placeholder(&self) -> &str {
util::assigned_str(&self.placeholder)
}
pub fn has_autofocus(&self) -> bool {
match &self.autofocus {
Some(_) => true,
_ => false
}
}
pub fn has_autocomplete(&self) -> bool {
match &self.autocomplete {
Some(_) => false,
_ => true
}
}
pub fn is_disabled(&self) -> bool {
match &self.disabled {
Some(_) => true,
_ => false
}
}
pub fn is_readonly(&self) -> bool {
match &self.readonly {
Some(_) => true,
_ => false
}
}
pub fn is_required(&self) -> bool {
match &self.required {
Some(_) => true,
_ => false
}
}
pub fn help_text(&self) -> &str {
util::assigned_str(&self.help_text)
}
pub fn template(&self) -> &str {
self.template.as_str()
}
}
fn always() -> bool {
true
}

View file

@ -1,131 +0,0 @@
use crate::prelude::*;
pub enum FormMethod {Get, Post}
pub struct Form {
renderable: fn() -> bool,
weight : i8,
id : Option<String>,
action : Option<String>,
method : FormMethod,
charset : Option<String>,
elements : PageContainer,
template : String,
}
impl PageComponent for Form {
fn prepare() -> Self {
Form {
renderable: always,
weight : 0,
id : None,
action : None,
method : FormMethod::Post,
charset : Some("UTF-8".to_owned()),
elements : 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 {
let method = match self.method {
FormMethod::Get => None,
FormMethod::Post => Some("post".to_owned())
};
html! {
form
id=[&self.id]
action=[&self.action]
method=[method]
accept-charset=[&self.charset]
{
div {
(self.elements.render(assets))
}
}
}
}
}
impl Form {
// Form 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 = util::valid_id(id);
self
}
pub fn with_action(mut self, action: &str) -> Self {
self.action = util::optional_str(action);
self
}
pub fn with_method(mut self, method: FormMethod) -> Self {
self.method = method;
self
}
pub fn with_charset(mut self, charset: &str) -> Self {
self.charset = util::optional_str(charset);
self
}
pub fn add(mut self, element: impl PageComponent) -> Self {
self.elements.add(element);
self
}
pub fn using_template(mut self, template: &str) -> Self {
self.template = template.to_owned();
self
}
// Form GETTERS.
pub fn id(&self) -> &str {
util::assigned_str(&self.id)
}
pub fn action(&self) -> &str {
util::assigned_str(&self.action)
}
pub fn method(&self) -> &str {
match &self.method {
FormMethod::Get => "get",
FormMethod::Post => "post"
}
}
pub fn charset(&self) -> &str {
util::assigned_str(&self.charset)
}
pub fn template(&self) -> &str {
self.template.as_str()
}
}
fn always() -> bool {
true
}

View file

@ -1,70 +0,0 @@
use crate::prelude::*;
pub struct Hidden {
weight : i8,
name : Option<String>,
value : Option<String>,
}
impl PageComponent for Hidden {
fn prepare() -> Self {
Hidden {
weight : 0,
name : None,
value : None,
}
}
fn weight(&self) -> i8 {
self.weight
}
fn default_render(&self, _: &mut PageAssets) -> Markup {
let id_item = match &self.name {
Some(name) => Some(format!("value-{}", name)),
_ => None
};
html! {
input
type="hidden"
id=[&id_item]
name=[&self.name]
value=[&self.value];
}
}
}
impl Hidden {
pub fn set(name: &str, value: &str) -> Self {
Hidden::prepare().with_name(name).with_value(value)
}
// Hidden BUILDER.
pub fn with_weight(mut self, weight: i8) -> Self {
self.weight = weight;
self
}
pub fn with_name(mut self, name: &str) -> Self {
self.name = util::valid_id(name);
self
}
pub fn with_value(mut self, value: &str) -> Self {
self.value = util::optional_str(value);
self
}
// Hidden GETTERS.
pub fn name(&self) -> &str {
util::assigned_str(&self.name)
}
pub fn value(&self) -> &str {
util::assigned_str(&self.value)
}
}

View file

@ -1,325 +0,0 @@
use crate::prelude::*;
enum InputType {Email, Password, Search, Telephone, Textfield, Url}
pub struct Input {
renderable : fn() -> bool,
weight : i8,
input_type : InputType,
name : Option<String>,
value : Option<String>,
label : Option<String>,
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>,
template : String,
}
impl PageComponent for Input {
fn prepare() -> Self {
Input {
renderable : always,
weight : 0,
input_type : InputType::Textfield,
name : None,
value : None,
label : None,
size : Some(60),
minlength : None,
maxlength : Some(128),
placeholder : None,
autofocus : None,
autocomplete: None,
disabled : None,
readonly : None,
required : None,
help_text : 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 {
let (input_type, class_type) = match &self.input_type {
InputType::Email => ("email", "form-type-email"),
InputType::Password => ("password", "form-type-password"),
InputType::Search => ("search", "form-type-search"),
InputType::Telephone => ("tel", "form-type-telephone"),
InputType::Textfield => ("text", "form-type-textfield"),
InputType::Url => ("url", "form-type-url")
};
let (class_item, id_item) = match &self.name {
Some(name) => (
format!("form-item form-item-{} {}", name, class_type),
Some(format!("edit-{}", name))
),
None => (
format!("form-item {}", class_type),
None
)
};
html! {
div class=(class_item) {
@if self.label != None {
label class="form-label" for=[&id_item] {
(self.label()) " "
@if self.required != None {
span
class="form-required"
title="Este campo es obligatorio."
{
"*"
} " "
}
}
}
input
type=(input_type)
id=[&id_item]
class="form-control"
name=[&self.name]
value=[&self.value]
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 {
div class="form-text" {
(self.help_text())
}
}
}
}
}
}
impl Input {
pub fn textfield() -> Self {
Input::prepare()
}
pub fn password() -> Self {
let mut input = Input::prepare();
input.input_type = InputType::Password;
input
}
pub fn search() -> Self {
let mut input = Input::prepare();
input.input_type = InputType::Search;
input
}
pub fn email() -> Self {
let mut input = Input::prepare();
input.input_type = InputType::Email;
input
}
pub fn telephone() -> Self {
let mut input = Input::prepare();
input.input_type = InputType::Telephone;
input
}
pub fn url() -> Self {
let mut input = Input::prepare();
input.input_type = InputType::Url;
input
}
// Input 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_name(mut self, name: &str) -> Self {
self.name = util::valid_id(name);
self
}
pub fn with_value(mut self, value: &str) -> Self {
self.value = util::optional_str(value);
self
}
pub fn with_label(mut self, label: &str) -> Self {
self.label = util::optional_str(label);
self
}
pub fn with_size(mut self, size: Option<u16>) -> Self {
self.size = size;
self
}
pub fn with_minlength(mut self, minlength: Option<u16>) -> Self {
self.minlength = minlength;
self
}
pub fn with_maxlength(mut self, maxlength: Option<u16>) -> Self {
self.maxlength = maxlength;
self
}
pub fn with_placeholder(mut self, placeholder: &str) -> Self {
self.placeholder = util::optional_str(placeholder);
self
}
pub fn autofocus(mut self, toggle: bool) -> Self {
self.autofocus = match toggle {
true => Some("autofocus".to_owned()),
false => None
};
self
}
pub fn autocomplete(mut self, toggle: bool) -> Self {
self.autocomplete = match toggle {
true => None,
false => Some("off".to_owned())
};
self
}
pub fn disabled(mut self, toggle: bool) -> Self {
self.disabled = match toggle {
true => Some("disabled".to_owned()),
false => None
};
self
}
pub fn readonly(mut self, toggle: bool) -> Self {
self.readonly = match toggle {
true => Some("readonly".to_owned()),
false => None
};
self
}
pub fn required(mut self, toggle: bool) -> Self {
self.required = match toggle {
true => Some("required".to_owned()),
false => None
};
self
}
pub fn with_help_text(mut self, help_text: &str) -> Self {
self.help_text = util::optional_str(help_text);
self
}
pub fn using_template(mut self, template: &str) -> Self {
self.template = template.to_owned();
self
}
// Input GETTERS.
pub fn name(&self) -> &str {
util::assigned_str(&self.name)
}
pub fn value(&self) -> &str {
util::assigned_str(&self.value)
}
pub fn label(&self) -> &str {
util::assigned_str(&self.label)
}
pub fn size(&self) -> Option<u16> {
self.size
}
pub fn minlength(&self) -> Option<u16> {
self.minlength
}
pub fn maxlength(&self) -> Option<u16> {
self.maxlength
}
pub fn placeholder(&self) -> &str {
util::assigned_str(&self.placeholder)
}
pub fn has_autofocus(&self) -> bool {
match &self.autofocus {
Some(_) => true,
_ => false
}
}
pub fn has_autocomplete(&self) -> bool {
match &self.autocomplete {
Some(_) => false,
_ => true
}
}
pub fn is_disabled(&self) -> bool {
match &self.disabled {
Some(_) => true,
_ => false
}
}
pub fn is_readonly(&self) -> bool {
match &self.readonly {
Some(_) => true,
_ => false
}
}
pub fn is_required(&self) -> bool {
match &self.required {
Some(_) => true,
_ => false
}
}
pub fn help_text(&self) -> &str {
util::assigned_str(&self.help_text)
}
pub fn template(&self) -> &str {
self.template.as_str()
}
}
fn always() -> bool {
true
}

View file

@ -1,11 +0,0 @@
mod form;
pub use form::{Form, FormMethod};
mod input;
pub use input::Input;
mod hidden;
pub use hidden::Hidden;
mod date;
pub use date::Date;
mod button;
pub use button::Button;

View file

@ -1,252 +0,0 @@
use crate::prelude::*;
enum MenuItemType {
Label(String),
Link(String, String),
LinkBlank(String, String),
Markup(Markup),
Separator,
Submenu(String, Menu),
}
// -----------------------------------------------------------------------------
// MenuItem.
// -----------------------------------------------------------------------------
pub struct MenuItem {
renderable: fn() -> bool,
weight : i8,
item_type : Option<MenuItemType>,
}
impl PageComponent for MenuItem {
fn prepare() -> Self {
MenuItem {
renderable: always,
weight : 0,
item_type : None,
}
}
fn is_renderable(&self) -> bool {
(self.renderable)()
}
fn weight(&self) -> i8 {
self.weight
}
fn default_render(&self, assets: &mut PageAssets) -> Markup {
match &self.item_type {
Some(MenuItemType::Label(label)) => html! {
li class="label" { a href="#" { (label) } }
},
Some(MenuItemType::Link(label, path)) => html! {
li class="link" { a href=(path) { (label) } }
},
Some(MenuItemType::LinkBlank(label, path)) => html! {
li class="link_blank" {
a href=(path) target="_blank" { (label) }
}
},
Some(MenuItemType::Markup(markup)) => html! {
li class="markup" { (*markup) }
},
Some(MenuItemType::Submenu(label, menu)) => html! {
li class="submenu" {
a href="#" { (label) }
ul {
(menu.render_items(assets))
}
}
},
Some(MenuItemType::Separator) => html! {
li class="separator" { }
},
None => html! {}
}
}
}
impl MenuItem {
pub fn label(label: &str) -> Self {
MenuItem {
renderable: always,
weight : 0,
item_type : Some(MenuItemType::Label(label.to_owned())),
}
}
pub fn link(label: &str, path: &str) -> Self {
MenuItem {
renderable: always,
weight : 0,
item_type : Some(MenuItemType::Link(
label.to_owned(),
path.to_owned(),
)),
}
}
pub fn link_blank(label: &str, path: &str) -> Self {
MenuItem {
renderable: always,
weight : 0,
item_type : Some(MenuItemType::LinkBlank(
label.to_owned(),
path.to_owned(),
)),
}
}
pub fn markup(markup: Markup) -> Self {
MenuItem {
renderable: always,
weight : 0,
item_type : Some(MenuItemType::Markup(markup)),
}
}
pub fn separator() -> Self {
MenuItem {
renderable: always,
weight : 0,
item_type : Some(MenuItemType::Separator),
}
}
pub fn submenu(label: &str, menu: Menu) -> Self {
MenuItem {
renderable: always,
weight : 0,
item_type : Some(MenuItemType::Submenu(
label.to_owned(),
menu
)),
}
}
// MenuItem 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
}
}
// -----------------------------------------------------------------------------
// Menu.
// -----------------------------------------------------------------------------
pub struct Menu {
renderable: fn() -> bool,
weight : i8,
id : Option<String>,
items : PageContainer,
template : String,
}
impl PageComponent for Menu {
fn prepare() -> Self {
Menu {
renderable: always,
weight : 0,
id : None,
items : 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 {
assets
.add_stylesheet(StyleSheet::source(
"/theme/menu/css/menu.css?ver=1.1.1"
))
.add_stylesheet(StyleSheet::source(
"/theme/menu/css/menu-clean.css?ver=1.1.1"
))
.add_javascript(JavaScript::source(
"/theme/menu/js/menu.min.js?ver=1.1.1"
))
.add_jquery();
let id = assets.serial_id(self.name(), self.id());
html! {
ul id=(id) class="sm sm-clean" {
(self.render_items(assets))
}
script type="text/javascript" defer {
"jQuery(function(){jQuery('#" (id) "').smartmenus({"
"hideTimeout: 0,"
"showTimeout: 80,"
"});});"
}
}
}
}
impl Menu {
// Menu 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 = util::valid_id(id);
self
}
pub fn add(mut self, item: MenuItem) -> Self {
self.items.add(item);
self
}
pub fn using_template(mut self, template: &str) -> Self {
self.template = template.to_owned();
self
}
// Menu GETTERS.
pub fn id(&self) -> &str {
util::assigned_str(&self.id)
}
pub fn template(&self) -> &str {
self.template.as_str()
}
// Menu EXTRAS.
pub fn render_items(&self, assets: &mut PageAssets) -> Markup {
html! { (self.items.render(assets)) }
}
}
fn always() -> bool {
true
}

View file

@ -1,11 +0,0 @@
mod container;
pub use container::Container;
mod chunck;
pub use chunck::Chunck;
mod block;
pub use block::Block;
mod menu;
pub use menu::{Menu, MenuItem};
pub mod form;
pub use form::{Form, FormMethod};

View file

@ -1,5 +0,0 @@
//! Temas, Módulos y Componentes base.
pub mod theme;
pub mod module;
pub mod component;

View file

@ -1,2 +0,0 @@
module_fullname = Admin module
module_description = Administration module.

View file

@ -1,2 +0,0 @@
module_fullname = Admin module
module_description = Módulo de administración.

View file

@ -1,28 +0,0 @@
use crate::prelude::*;
localize!("en-US", "src/base/module/admin/locales");
mod summary;
pub struct AdminModule;
impl Module for AdminModule {
fn name(&self) -> &'static str {
"admin"
}
fn fullname(&self) -> String {
l("module_fullname")
}
fn description(&self) -> Option<String> {
Some(l("module_description"))
}
fn configure_module(&self, cfg: &mut server::web::ServiceConfig) {
cfg.service(
server::web::scope("/admin")
.route("", server::web::get().to(summary::summary))
);
}
}

View file

@ -1,58 +0,0 @@
use crate::prelude::*;
use super::l;
pub async fn summary() -> server::Result<Markup> {
let top_menu = Menu::prepare()
.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::label("Opción 1"))
.add(MenuItem::label("Opción 2"))
))
.add(MenuItem::separator())
.add(MenuItem::submenu("Submenú 2", Menu::prepare()
.add(MenuItem::label("Opción 1"))
.add(MenuItem::label("Opción 2"))
))
.add(MenuItem::label("Opción 4"));
let side_menu = Menu::prepare()
.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::label("Opción 1"))
.add(MenuItem::label("Opción 2"))
))
.add(MenuItem::separator())
.add(MenuItem::submenu("Submenú 2", Menu::prepare()
.add(MenuItem::label("Opción 1"))
.add(MenuItem::label("Opción 2"))
))
.add(MenuItem::label("Opción 4"));
Page::prepare()
.using_theme("bootsier")
.with_title("Admin")
.add_to("top-menu", top_menu)
.add_to("content", Container::row()
.add(Container::column()
.add(side_menu)
)
.add(Container::column()
.add(Chunck::markup(html! {
p { "Columna 2"}
}))
)
)
.using_template("admin")
.render()
}

View file

@ -1,21 +0,0 @@
module_fullname = Default homepage
module_description = Displays a default 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.
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.
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".
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!
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.

View file

@ -1,21 +0,0 @@
module_fullname = Página de inicio predeterminada
module_description = Muestra una página de inicio predeterminada cuando no hay ninguna configurada.
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.
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.
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".
title_promo_pagetop = Promociona PageTop
text1_promo_pagetop = Puede 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í.

View file

@ -1,74 +0,0 @@
use crate::prelude::*;
localize!("en-US", "src/base/module/homepage/locales");
pub struct HomepageModule;
impl Module for HomepageModule {
fn name(&self) -> &'static str {
"homepage"
}
fn fullname(&self) -> String {
l("module_fullname")
}
fn description(&self) -> Option<String> {
Some(l("module_description"))
}
fn configure_module(&self, cfg: &mut server::web::ServiceConfig) {
cfg.route("/", server::web::get().to(home));
}
}
async fn home() -> server::Result<Markup> {
Page::prepare()
.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")) }
}))
)
.render()
}

View file

@ -1,3 +0,0 @@
pub mod admin;
pub mod homepage;
pub mod user;

View file

@ -1 +0,0 @@
pub mod user;

View file

@ -1,18 +0,0 @@
use crate::db::entity::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
#[sea_orm(table_name = "user")]
pub struct Model {
#[sea_orm(primary_key)]
#[serde(skip_deserializing)]
pub id: i32,
pub title: String,
#[sea_orm(column_type = "Text")]
pub text: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}

View file

@ -1,8 +0,0 @@
module_fullname = User
module_description = Manages the user registration and login system.
username = User name
password = Password
username_help = Enter your { $app } username.
password_help = Enter the password that accompanies your username.
login = Log in

View file

@ -1,8 +0,0 @@
module_fullname = Usuario
module_description = Gestion el registro de usuarios y el sistema de accesos.
username = Nombre de usuario
password = Contraseña
username_help = Introduzca su nombre de usuario en { $app }.
password_help = Introduzca la contraseña asociada a su nombre de usuario.
login = Iniciar sesión

View file

@ -1,54 +0,0 @@
use crate::db::migration::*;
#[derive(Iden)]
enum User {
Table,
Id,
Title,
Text,
}
pub struct Migration;
impl MigrationName for Migration {
fn name(&self) -> &str {
"m20220312_000001_create_table_user"
}
}
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(User::Table)
.if_not_exists()
.col(ColumnDef::new(User::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(User::Title)
.string()
.not_null()
)
.col(ColumnDef::new(User::Text)
.string()
.not_null()
)
.to_owned()
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop()
.table(User::Table)
.to_owned()
)
.await
}
}

View file

@ -1,12 +0,0 @@
use crate::db::migration::*;
pub mod m20220312_000001_create_table_user;
pub struct Migrator;
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![Box::new(m20220312_000001_create_table_user::Migration)]
}
}

View file

@ -1,61 +0,0 @@
use crate::prelude::*;
localize!("en-US", "src/base/module/user/locales");
mod entity;
mod migration;
pub struct UserModule;
impl Module for UserModule {
fn name(&self) -> &'static str {
"user"
}
fn fullname(&self) -> String {
l("module_fullname")
}
fn description(&self) -> Option<String> {
Some(l("module_description"))
}
fn configure_module(&self, cfg: &mut server::web::ServiceConfig) {
cfg.route("/user/login", server::web::get().to(login));
}
fn migrations(&self, dbconn: &db::DbConn) -> Result<(), db::DbErr> {
db_migrations!(dbconn)
}
}
fn form_login() -> impl PageComponent {
Form::prepare()
.with_id("user-login")
.add(form::Input::textfield()
.with_name("name")
.with_label(l("username").as_str())
.with_help_text(t("username_help", &args![
"app" => SETTINGS.app.name.to_owned()
]).as_str())
.autofocus(true)
)
.add(form::Input::password()
.with_name("pass")
.with_label(l("password").as_str())
.with_help_text(l("password_help").as_str())
)
.add(form::Button::submit(l("login").as_str()))
}
async fn login() -> server::Result<Markup> {
Page::prepare()
.with_title(
"Identificación del usuario"
)
.add_to("content", Container::prepare()
.with_id("welcome")
.add(form_login())
)
.render()
}

View file

@ -1,32 +0,0 @@
use crate::prelude::*;
include!(concat!(env!("OUT_DIR"), "/aliner.rs"));
pub struct AlinerTheme;
impl Theme for AlinerTheme {
fn name(&self) -> &'static str {
"aliner"
}
fn fullname(&self) -> String {
"Aliner".to_owned()
}
fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) {
cfg.service(actix_web_static_files::ResourceFiles::new(
"/aliner",
assets()
));
}
fn before_render_page(&self, page: &mut Page) {
page.assets()
.add_stylesheet(
StyleSheet::source(
"/aliner/css/styles.css"
)
.with_weight(-99)
);
}
}

View file

@ -1,5 +0,0 @@
e404-description = Oops! Page Not Found
e404-message = The page you are looking for may have been removed, had its name changed, or is temporarily unavailable.
e500-description = Oops! Unexpected Error
e500-message = We're having an issue. Please report this error to an administrator.
back-homepage = Back to homepage

View file

@ -1,5 +0,0 @@
e404-description = ¡Vaya! Página No Encontrada
e404-message = La página que está buscando puede haber sido eliminada, cambiada de nombre o no está disponible temporalmente.
e500-description = ¡Vaya! Error Inesperado
e500-message = Está ocurriendo una incidencia. Por favor, informe de este error a un administrador.
back-homepage = Volver al inicio

View file

@ -1,86 +0,0 @@
use crate::prelude::*;
include!(concat!(env!("OUT_DIR"), "/bootsier.rs"));
localize!("en-US", "src/base/theme/bootsier/locales");
pub struct BootsierTheme;
impl Theme for BootsierTheme {
fn name(&self) -> &'static str {
"bootsier"
}
fn fullname(&self) -> String {
"Bootsier".to_owned()
}
fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) {
cfg.service(actix_web_static_files::ResourceFiles::new(
"/bootsier",
assets()
));
}
fn before_render_page(&self, page: &mut Page) {
page.assets()
.with_favicon(
Favicon::new()
.with_icon("/bootsier/favicon.png")
)
.add_stylesheet(
StyleSheet::source(
"/bootsier/css/bootstrap.min.css?ver=5.1.3"
)
.with_weight(-99)
)
.add_javascript(
JavaScript::source(
"/bootsier/js/bootstrap.bundle.min.js?ver=5.1.3"
)
.with_weight(-99)
)
.add_jquery();
}
fn render_error_page(&self, mut s: server::http::StatusCode) -> server::Result<Markup> {
let mut description = "e500-description";
let mut message = "e500-description";
match s {
server::http::StatusCode::NOT_FOUND => {
description = "e404-description";
message = "e404-message";
},
_ => {
s = server::http::StatusCode::INTERNAL_SERVER_ERROR;
}
}
Page::prepare()
.with_title(format!("Error {}", s.as_str()).as_str())
.add_to("content", Chunck::markup(html! {
div class="jumbotron" {
div class="media" {
img
src="/bootsier/images/caution.png"
class="mr-4"
style="width: 20%; max-width: 188px"
alt="Caution!";
div class="media-body" {
h1 class="display-4" { (s) }
p class="lead" { (l(description)) }
hr class="my-4";
p { (l(message)) }
a
class="btn btn-primary btn-lg"
href="/"
role="button"
{
(l("back-homepage"))
}
}
}
}
}))
.render()
}
}

View file

@ -1,13 +0,0 @@
use crate::prelude::*;
pub struct MinimalTheme;
impl Theme for MinimalTheme {
fn name(&self) -> &'static str {
"minimal"
}
fn fullname(&self) -> String {
"Minimal".to_owned()
}
}

View file

@ -1,3 +0,0 @@
pub mod aliner;
pub mod minimal;
pub mod bootsier;