Libera la versión de desarrollo 0.0.4
This commit is contained in:
parent
d72e1ccad5
commit
5b1064fda2
27 changed files with 104 additions and 67 deletions
11
CREDITS.md
11
CREDITS.md
|
|
@ -1,9 +1,9 @@
|
|||
# FIGfonts
|
||||
|
||||
PageTop utiliza el paquete [figlet-rs](https://crates.io/crates/figlet-rs) de
|
||||
*yuanbohan*, que muestra al inicio de la ejecución un rótulo con el nombre de
|
||||
*yuanbohan*. Muestra en el terminal un rótulo de presentación con el nombre de
|
||||
la aplicación usando caracteres [FIGlet](http://www.figlet.org/). Las fuentes
|
||||
incluidas en `resources` son:
|
||||
incluidas en `src/app/banner` son:
|
||||
|
||||
* [slant.flf](http://www.figlet.org/fontdb_example.cgi?font=slant.flf)
|
||||
por *Glenn Chappell*.
|
||||
|
|
@ -13,3 +13,10 @@ incluidas en `resources` son:
|
|||
por *Claude Martins*.
|
||||
* [starwars.flf](http://www.figlet.org/fontdb_example.cgi?font=starwars.flf)
|
||||
por *Ryan Youck*.
|
||||
|
||||
# Icono
|
||||
|
||||
El monstruo sonriente de Frankenstein es una divertida creación de
|
||||
[Webalys](https://www.iconfinder.com/webalys). Puede encontrarse en su colección
|
||||
[Nasty Icons](https://www.iconfinder.com/iconsets/nasty) disponible en
|
||||
[ICONFINDER](https://www.iconfinder.com/).
|
||||
|
|
@ -15,7 +15,7 @@ db_user = "drust"
|
|||
db_pass = "DrU__#3T"
|
||||
|
||||
[log]
|
||||
tracing = "Info,sqlx::query=Warn"
|
||||
tracing = "Info,pagetop=Debug,sqlx::query=Warn"
|
||||
|
||||
[dev]
|
||||
#static_files = "pagetop/static"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ mod summary;
|
|||
pub struct AdminModule;
|
||||
|
||||
impl ModuleTrait for AdminModule {
|
||||
fn name(&self) -> &'static str {
|
||||
"Admin"
|
||||
}
|
||||
|
||||
fn fullname(&self) -> String {
|
||||
l("module_fullname")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ mod migration;
|
|||
pub struct NodeModule;
|
||||
|
||||
impl ModuleTrait for NodeModule {
|
||||
fn name(&self) -> &'static str {
|
||||
"Node"
|
||||
}
|
||||
|
||||
fn fullname(&self) -> String {
|
||||
l("module_fullname")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ mod migration;
|
|||
pub struct UserModule;
|
||||
|
||||
impl ModuleTrait for UserModule {
|
||||
fn name(&self) -> &'static str {
|
||||
"User"
|
||||
}
|
||||
|
||||
fn fullname(&self) -> String {
|
||||
l("module_fullname")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pagetop"
|
||||
version = "0.0.3"
|
||||
version = "0.0.4"
|
||||
edition = "2021"
|
||||
|
||||
authors = [
|
||||
|
|
|
|||
|
|
@ -27,13 +27,18 @@ impl Application {
|
|||
#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))]
|
||||
Lazy::force(&app::db::DBCONN);
|
||||
|
||||
// Registra los temas predeterminados.
|
||||
theme::register_theme(&base::theme::aliner::AlinerTheme);
|
||||
theme::register_theme(&base::theme::minimal::MinimalTheme);
|
||||
theme::register_theme(&base::theme::bootsier::BootsierTheme);
|
||||
|
||||
// Ejecuta la función de inicio de la aplicación.
|
||||
trace::info!("Calling application bootstrap");
|
||||
let _ = &bootstrap();
|
||||
|
||||
// Registra el módulo para una página de presentación de PageTop.
|
||||
// Registra el módulo de presentación de PageTop.
|
||||
// Normalmente se sobrecargará en la función de inicio.
|
||||
module::register_module(&base::module::homepage::HomepageModule);
|
||||
module::register_module(&base::module::demopage::DemopageModule);
|
||||
|
||||
// Actualizaciones pendientes de la base de datos (opcional).
|
||||
#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))]
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ impl Block {
|
|||
}
|
||||
|
||||
pub fn with_title(mut self, title: &str) -> Self {
|
||||
self.title = util::optional_str(title);
|
||||
self.title = util::valid_str(title);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ impl Button {
|
|||
}
|
||||
|
||||
pub fn with_value(mut self, value: &str) -> Self {
|
||||
self.value = util::optional_str(value);
|
||||
self.value = util::valid_str(value);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,17 +112,17 @@ impl Date {
|
|||
}
|
||||
|
||||
pub fn with_value(mut self, value: &str) -> Self {
|
||||
self.value = util::optional_str(value);
|
||||
self.value = util::valid_str(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_label(mut self, label: &str) -> Self {
|
||||
self.label = util::optional_str(label);
|
||||
self.label = util::valid_str(label);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_placeholder(mut self, placeholder: &str) -> Self {
|
||||
self.placeholder = util::optional_str(placeholder);
|
||||
self.placeholder = util::valid_str(placeholder);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +167,7 @@ impl Date {
|
|||
}
|
||||
|
||||
pub fn with_help_text(mut self, help_text: &str) -> Self {
|
||||
self.help_text = util::optional_str(help_text);
|
||||
self.help_text = util::valid_str(help_text);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ impl Form {
|
|||
}
|
||||
|
||||
pub fn with_action(mut self, action: &str) -> Self {
|
||||
self.action = util::optional_str(action);
|
||||
self.action = util::valid_str(action);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ impl Form {
|
|||
}
|
||||
|
||||
pub fn with_charset(mut self, charset: &str) -> Self {
|
||||
self.charset = util::optional_str(charset);
|
||||
self.charset = util::valid_str(charset);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ impl Hidden {
|
|||
}
|
||||
|
||||
pub fn with_value(mut self, value: &str) -> Self {
|
||||
self.value = util::optional_str(value);
|
||||
self.value = util::valid_str(value);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,12 +167,12 @@ impl Input {
|
|||
}
|
||||
|
||||
pub fn with_value(mut self, value: &str) -> Self {
|
||||
self.value = util::optional_str(value);
|
||||
self.value = util::valid_str(value);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_label(mut self, label: &str) -> Self {
|
||||
self.label = util::optional_str(label);
|
||||
self.label = util::valid_str(label);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -192,7 +192,7 @@ impl Input {
|
|||
}
|
||||
|
||||
pub fn with_placeholder(mut self, placeholder: &str) -> Self {
|
||||
self.placeholder = util::optional_str(placeholder);
|
||||
self.placeholder = util::valid_str(placeholder);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ impl Input {
|
|||
}
|
||||
|
||||
pub fn with_help_text(mut self, help_text: &str) -> Self {
|
||||
self.help_text = util::optional_str(help_text);
|
||||
self.help_text = util::valid_str(help_text);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
module_fullname = Default homepage
|
||||
module_description = Displays a default homepage when none is configured.
|
||||
module_description = Displays a demo homepage when none is configured.
|
||||
|
||||
page_title = Hello world!
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
module_fullname = Página de inicio predeterminada
|
||||
module_description = Muestra una página de inicio predeterminada cuando no hay ninguna configurada.
|
||||
module_description = Muestra una página de demostración predeterminada cuando no hay ninguna configurada.
|
||||
|
||||
page_title = ¡Hola mundo!
|
||||
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
localize!("src/base/module/homepage/locales");
|
||||
localize!("src/base/module/demopage/locales");
|
||||
|
||||
pub struct HomepageModule;
|
||||
pub struct DemopageModule;
|
||||
|
||||
impl ModuleTrait for DemopageModule {
|
||||
fn name(&self) -> &'static str {
|
||||
"Demopage"
|
||||
}
|
||||
|
||||
impl ModuleTrait for HomepageModule {
|
||||
fn fullname(&self) -> String {
|
||||
l("module_fullname")
|
||||
}
|
||||
|
|
@ -20,9 +24,13 @@ impl ModuleTrait for HomepageModule {
|
|||
|
||||
async fn home() -> app::Result<Markup> {
|
||||
Page::prepare()
|
||||
.using_theme("Bootsier")
|
||||
.with_title(
|
||||
l("page_title").as_str()
|
||||
)
|
||||
|
||||
|
||||
|
||||
.add_to("content", Container::prepare()
|
||||
.with_id("welcome")
|
||||
.add(Chunck::markup(html! {
|
||||
|
|
@ -1 +1 @@
|
|||
pub mod homepage;
|
||||
pub mod demopage;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ pub struct AlinerTheme;
|
|||
|
||||
impl ThemeTrait for AlinerTheme {
|
||||
fn name(&self) -> &'static str {
|
||||
"aliner"
|
||||
"Aliner"
|
||||
}
|
||||
|
||||
fn fullname(&self) -> String {
|
||||
|
|
@ -19,6 +19,10 @@ impl ThemeTrait for AlinerTheme {
|
|||
|
||||
fn before_render_page(&self, page: &mut Page) {
|
||||
page.assets()
|
||||
.with_favicon(
|
||||
Favicon::new()
|
||||
.with_icon("/theme/favicon.png")
|
||||
)
|
||||
.add_stylesheet(
|
||||
StyleSheet::source(
|
||||
"/aliner/css/styles.css"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ pub struct BootsierTheme;
|
|||
|
||||
impl ThemeTrait for BootsierTheme {
|
||||
fn name(&self) -> &'static str {
|
||||
"bootsier"
|
||||
"Bootsier"
|
||||
}
|
||||
|
||||
fn fullname(&self) -> String {
|
||||
|
|
@ -23,7 +23,7 @@ impl ThemeTrait for BootsierTheme {
|
|||
page.assets()
|
||||
.with_favicon(
|
||||
Favicon::new()
|
||||
.with_icon("/bootsier/favicon.png")
|
||||
.with_icon("/theme/favicon.png")
|
||||
)
|
||||
.add_stylesheet(
|
||||
StyleSheet::source(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ pub struct MinimalTheme;
|
|||
|
||||
impl ThemeTrait for MinimalTheme {
|
||||
fn name(&self) -> &'static str {
|
||||
"minimal"
|
||||
"Minimal"
|
||||
}
|
||||
|
||||
fn fullname(&self) -> String {
|
||||
|
|
|
|||
|
|
@ -10,13 +10,24 @@ static MODULES: Lazy<RwLock<Vec<&dyn ModuleTrait>>> = Lazy::new(|| {
|
|||
});
|
||||
|
||||
pub fn register_module(module: &'static dyn ModuleTrait) {
|
||||
let mut modules = MODULES.write().unwrap();
|
||||
match modules.iter().find(|m| m.name() == module.name()) {
|
||||
None => {
|
||||
trace::info!("{}", module.name());
|
||||
modules.push(module);
|
||||
},
|
||||
Some(_) => {},
|
||||
let mut list: Vec<&dyn ModuleTrait> = Vec::new();
|
||||
add_to(&mut list, module);
|
||||
list.reverse();
|
||||
MODULES.write().unwrap().append(&mut list);
|
||||
}
|
||||
|
||||
fn add_to(list: &mut Vec<&dyn ModuleTrait>, module: &'static dyn ModuleTrait) {
|
||||
if !MODULES.read().unwrap().iter().any(|m| m.name() == module.name()) {
|
||||
if !list.iter().any(|m| m.name() == module.name()) {
|
||||
trace::debug!("Registering \"{}\" module", module.name());
|
||||
list.push(module);
|
||||
|
||||
let mut dependencies = module.dependencies();
|
||||
dependencies.reverse();
|
||||
for d in dependencies.iter() {
|
||||
add_to(list, *d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,17 +3,9 @@ use crate::app;
|
|||
#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))]
|
||||
use crate::db;
|
||||
|
||||
use std::any::type_name;
|
||||
|
||||
/// Los módulos deben implementar este *trait*.
|
||||
pub trait ModuleTrait: Send + Sync {
|
||||
fn name(&self) -> &'static str {
|
||||
let name = type_name::<Self>();
|
||||
match name.rfind("::") {
|
||||
Some(position) => &name[(position + 2)..],
|
||||
None => name
|
||||
}
|
||||
}
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
fn fullname(&self) -> String;
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ impl<'a> Page<'a> {
|
|||
// Page BUILDER.
|
||||
|
||||
pub fn with_language(&mut self, language: &str) -> &mut Self {
|
||||
self.language = util::optional_str(language);
|
||||
self.language = util::valid_str(language);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -89,12 +89,12 @@ impl<'a> Page<'a> {
|
|||
}
|
||||
|
||||
pub fn with_title(&mut self, title: &str) -> &mut Self {
|
||||
self.title = util::optional_str(title);
|
||||
self.title = util::valid_str(title);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_description(&mut self, description: &str) -> &mut Self {
|
||||
self.description = util::optional_str(description);
|
||||
self.description = util::valid_str(description);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{Lazy, app, base, theme_static_files, trace};
|
||||
use crate::{Lazy, app, theme_static_files, trace};
|
||||
use super::ThemeTrait;
|
||||
|
||||
use std::sync::RwLock;
|
||||
|
|
@ -7,21 +7,14 @@ include!(concat!(env!("OUT_DIR"), "/theme.rs"));
|
|||
|
||||
// Temas registrados.
|
||||
static THEMES: Lazy<RwLock<Vec<&dyn ThemeTrait>>> = Lazy::new(|| {
|
||||
RwLock::new(vec![
|
||||
&base::theme::aliner::AlinerTheme,
|
||||
&base::theme::minimal::MinimalTheme,
|
||||
&base::theme::bootsier::BootsierTheme,
|
||||
])
|
||||
RwLock::new(Vec::new())
|
||||
});
|
||||
|
||||
pub fn register_theme(theme: &'static dyn ThemeTrait) {
|
||||
let mut themes = THEMES.write().unwrap();
|
||||
match themes.iter().find(|t| t.name() == theme.name()) {
|
||||
None => {
|
||||
trace::info!("{}", theme.name());
|
||||
themes.push(theme);
|
||||
},
|
||||
Some(_) => {},
|
||||
if !themes.iter().any(|t| t.name() == theme.name()) {
|
||||
trace::debug!("Registering \"{}\" theme", theme.name());
|
||||
themes.push(theme);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::app;
|
||||
use crate::config::SETTINGS;
|
||||
use crate::html::{Markup, html};
|
||||
use crate::response::page::{Page, PageAssets, PageComponent};
|
||||
use crate::response::page::{Favicon, Page, PageAssets, PageComponent};
|
||||
use crate::base::component::Chunck;
|
||||
|
||||
/// Los temas deben implementar este "trait".
|
||||
|
|
@ -20,6 +20,11 @@ pub trait ThemeTrait: Send + Sync {
|
|||
|
||||
#[allow(unused_variables)]
|
||||
fn before_render_page(&self, page: &mut Page) {
|
||||
page.assets()
|
||||
.with_favicon(
|
||||
Favicon::new()
|
||||
.with_icon("/theme/favicon.png")
|
||||
);
|
||||
}
|
||||
|
||||
fn render_page_head(&self, page: &mut Page) -> Markup {
|
||||
|
|
|
|||
|
|
@ -37,24 +37,24 @@ macro_rules! theme_static_files {
|
|||
}
|
||||
|
||||
pub fn valid_id(id: &str) -> Option<String> {
|
||||
let id = id.trim().replace(" ", "_").to_lowercase();
|
||||
let id = id.trim();
|
||||
match id.is_empty() {
|
||||
true => None,
|
||||
false => Some(id),
|
||||
false => Some(id.replace(" ", "_").to_lowercase()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optional_str(s: &str) -> Option<String> {
|
||||
let s = s.to_owned();
|
||||
pub fn valid_str(s: &str) -> Option<String> {
|
||||
let s = s.trim();
|
||||
match s.is_empty() {
|
||||
true => None,
|
||||
false => Some(s),
|
||||
false => Some(s.to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assigned_str(optional: &Option<String>) -> &str {
|
||||
match optional {
|
||||
Some(o) => o.as_str(),
|
||||
_ => "",
|
||||
None => "",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
pagetop/static/theme/favicon.png
Normal file
BIN
pagetop/static/theme/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Loading…
Add table
Add a link
Reference in a new issue