Añade soporte nativo a Bootstrap con un nuevo tema

This commit is contained in:
Manuel Cillero 2022-02-21 00:28:22 +01:00
parent d38df3a5b6
commit 7f8b94eafe
37 changed files with 652 additions and 6 deletions

15
CREDITS.md Normal file
View file

@ -0,0 +1,15 @@
# FIGfonts
PageTop utiliza el paquete [figlet-rs](https://crates.io/crates/figlet-rs) de
*yuanbohan* para mostrar al inicio un rótulo con el nombre de la aplicación
usando [FIGlet](http://www.figlet.org/). Las fuentes incluidas en `resources`
son:
* [slant.flf](http://www.figlet.org/fontdb_example.cgi?font=slant.flf)
por *Glenn Chappell*.
* [small.flf](http://www.figlet.org/fontdb_example.cgi?font=small.flf)
por *Glenn Chappell*, usado por defecto.
* [speed.flf](http://www.figlet.org/fontdb_example.cgi?font=speed.flf)
por *Claude Martins*.
* [starwars.flf](http://www.figlet.org/fontdb_example.cgi?font=starwars.flf)
por *Ryan Youck*.

View file

@ -41,12 +41,17 @@ fluent-templates = "0.6.1"
unic-langid = "0.9.0"
actix-web = "3.3.3"
actix-web-static-files = "3.0.5"
maud = { version = "0.23.0", features = ["actix-web"] }
sycamore = { version = "0.7.1", features = ["ssr"] }
downcast-rs = "1.2.0"
serde = { version = "1.0", features = ["derive"] }
[build-dependencies]
actix-web-static-files = "3.0.5"
[lib]
name = "pagetop"

31
build.rs Normal file
View file

@ -0,0 +1,31 @@
use actix_web_static_files::resource_dir;
use std::env;
use std::path::Path;
fn main() {
resource_dir("./resources/assets")
.with_generated_filename(
Path::new(env::var("OUT_DIR").unwrap().as_str())
.join("assets.rs")
)
.with_generated_fn("assets")
.build()
.unwrap();
resource_dir("./src/base/theme/aliner/assets")
.with_generated_filename(
Path::new(env::var("OUT_DIR").unwrap().as_str())
.join("aliner.rs")
)
.build()
.unwrap();
resource_dir("./src/base/theme/bootsier/assets")
.with_generated_filename(
Path::new(env::var("OUT_DIR").unwrap().as_str())
.join("bootsier.rs")
)
.build()
.unwrap();
}

View file

@ -4,7 +4,7 @@ description = "Developed with the amazing PageTop framework."
# Idioma (localización) predeterminado.
language = "en-US"
# Tema predeterminado.
theme = "Minimal"
theme = "Bootsier"
# Rótulo al inicio: "Off", "Slant", "Small", "Speed" o "Starwars".
startup_banner = "Small"

2
resources/assets/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -34,7 +34,7 @@ impl PageComponent for Container {
fn default_render(&self, assets: &mut PageAssets) -> Markup {
let classes = match self.container {
ContainerType::Wrapper => "wrapper",
ContainerType::Wrapper => "container",
ContainerType::Row => "row",
ContainerType::Column => "col",
};

View file

@ -42,6 +42,9 @@ async fn login() -> server::Result<Markup> {
.with_title(
"Identificación del usuario"
)
.add_to("content", form_login())
.add_to("content", Container::prepare()
.with_id("welcome")
.add(form_login())
)
.render()
}

View file

@ -0,0 +1,343 @@
html {
background-color: white;
}
* * {
outline: 5px solid rgba(255,0,0,.1);
}
* * * {
outline: 3px dashed rgba(255,0,0,.4);
}
* * * * {
outline: 2px dotted rgba(255,0,0,.6);
}
* * * * * {
outline: 1px dotted rgba(255,0,0,.9);
}
* * * * * * {
outline-color: gray;
}
*::before, *::after {
background: #faa;
border-radius: 3px;
font: normal normal 400 10px/1.2 monospace;
padding: 1px 3px;
}
*::before {
content: "(";
}
*::after {
content: ")";
}
a::before { content: "<a>"; }
a::after { content: "</a>"; }
abbr::before { content: "<abbr>"; }
abbr::after { content: "</abbr>"; }
acronym::before { content: "<acronym>"; }
acronym::after { content: "</acronym>"; }
address::before { content: "<address>"; }
address::after { content: "</address>"; }
applet::before { content: "<applet>"; }
applet::after { content: "</applet>"; }
area::before { content: "<area>"; }
area::after { content: "</area>"; }
article::before { content: "<article>"; }
article::after { content: "</article>"; }
aside::before { content: "<aside>"; }
aside::after { content: "</aside>"; }
audio::before { content: "<audio>"; }
audio::after { content: "</audio>"; }
b::before { content: "<b>"; }
b::after { content: "</b>"; }
base::before { content: "<base>"; }
base::after { content: "</base>"; }
basefont::before { content: "<basefont>"; }
basefont::after { content: "</basefont>"; }
bdi::before { content: "<bdi>"; }
bdi::after { content: "</bdi>"; }
bdo::before { content: "<bdo>"; }
bdo::after { content: "</bdo>"; }
bgsound::before { content: "<bgsound>"; }
bgsound::after { content: "</bgsound>"; }
big::before { content: "<big>"; }
big::after { content: "</big>"; }
blink::before { content: "<blink>"; }
blink::after { content: "</blink>"; }
blockquote::before { content: "<blockquote>"; }
blockquote::after { content: "</blockquote>"; }
body::before { content: "<body>"; }
body::after { content: "</body>"; }
br::before { content: "<br>"; }
br::after { content: "</br>"; }
button::before { content: "<button>"; }
button::after { content: "</button>"; }
caption::before { content: "<caption>"; }
caption::after { content: "</caption>"; }
canvas::before { content: "<canvas>"; }
canvas::after { content: "</canvas>"; }
center::before { content: "<center>"; }
center::after { content: "</center>"; }
cite::before { content: "<cite>"; }
cite::after { content: "</cite>"; }
code::before { content: "<code>"; }
code::after { content: "</code>"; }
col::before { content: "<col>"; }
col::after { content: "</col>"; }
colgroup::before { content: "<colgroup>"; }
colgroup::after { content: "</colgroup>"; }
command::before { content: "<command>"; }
command::after { content: "</command>"; }
content::before { content: "<content>"; }
content::after { content: "</content>"; }
data::before { content: "<data>"; }
data::after { content: "</data>"; }
datalist::before { content: "<datalist>"; }
datalist::after { content: "</datalist>"; }
dd::before { content: "<dd>"; }
dd::after { content: "</dd>"; }
del::before { content: "<del>"; }
del::after { content: "</del>"; }
details::before { content: "<details>"; }
details::after { content: "</details>"; }
dfn::before { content: "<dfn>"; }
dfn::after { content: "</dfn>"; }
dialog::before { content: "<dialog>"; }
dialog::after { content: "</dialog>"; }
dir::before { content: "<dir>"; }
dir::after { content: "</dir>"; }
div::before { content: "<div>"; }
div::after { content: "</div>"; }
dl::before { content: "<dl>"; }
dl::after { content: "</dl>"; }
dt::before { content: "<dt>"; }
dt::after { content: "</dt>"; }
element::before { content: "<element>"; }
element::after { content: "</element>"; }
em::before { content: "<em>"; }
em::after { content: "</em>"; }
embed::before { content: "<embed>"; }
embed::after { content: "</embed>"; }
fieldset::before { content: "<fieldset>"; }
fieldset::after { content: "</fieldset>"; }
figcaption::before { content: "<figcaption>"; }
figcaption::after { content: "</figcaption>"; }
figure::before { content: "<figure>"; }
figure::after { content: "</figure>"; }
font::before { content: "<font>"; }
font::after { content: "</font>"; }
footer::before { content: "<footer>"; }
footer::after { content: "</footer>"; }
form::before { content: "<form>"; }
form::after { content: "</form>"; }
frame::before { content: "<frame>"; }
frame::after { content: "</frame>"; }
frameset::before { content: "<frameset>"; }
frameset::after { content: "</frameset>"; }
h1::before { content: "<h1>"; }
h1::after { content: "</h1>"; }
h2::before { content: "<h2>"; }
h2::after { content: "</h2>"; }
h3::before { content: "<h3>"; }
h3::after { content: "</h3>"; }
h4::before { content: "<h4>"; }
h4::after { content: "</h4>"; }
h5::before { content: "<h5>"; }
h5::after { content: "</h5>"; }
h6::before { content: "<h6>"; }
h6::after { content: "</h6>"; }
head::before { content: "<head>"; }
head::after { content: "</head>"; }
header::before { content: "<header>"; }
header::after { content: "</header>"; }
hgroup::before { content: "<hgroup>"; }
hgroup::after { content: "</hgroup>"; }
hr::before { content: "<hr>"; }
hr::after { content: "</hr>"; }
html::before { content: "<html>"; }
html::after { content: "</html>"; }
i::before { content: "<i>"; }
i::after { content: "</i>"; }
iframe::before { content: "<iframe>"; }
iframe::after { content: "</iframe>"; }
image::before { content: "<image>"; }
image::after { content: "</image>"; }
img::before { content: "<img>"; }
img::after { content: "</img>"; }
input::before { content: "<input>"; }
input::after { content: "</input>"; }
ins::before { content: "<ins>"; }
ins::after { content: "</ins>"; }
isindex::before { content: "<isindex>"; }
isindex::after { content: "</isindex>"; }
kbd::before { content: "<kbd>"; }
kbd::after { content: "</kbd>"; }
keygen::before { content: "<keygen>"; }
keygen::after { content: "</keygen>"; }
label::before { content: "<label>"; }
label::after { content: "</label>"; }
legend::before { content: "<legend>"; }
legend::after { content: "</legend>"; }
li::before { content: "<li>"; }
li::after { content: "</li>"; }
link::before { content: "<link>"; }
link::after { content: "</link>"; }
listing::before { content: "<listing>"; }
listing::after { content: "</listing>"; }
main::before { content: "<main>"; }
main::after { content: "</main>"; }
map::before { content: "<map>"; }
map::after { content: "</map>"; }
mark::before { content: "<mark>"; }
mark::after { content: "</mark>"; }
marquee::before { content: "<marquee>"; }
marquee::after { content: "</marquee>"; }
menu::before { content: "<menu>"; }
menu::after { content: "</menu>"; }
menuitem::before { content: "<menuitem>"; }
menuitem::after { content: "</menuitem>"; }
meta::before { content: "<meta>"; }
meta::after { content: "</meta>"; }
meter::before { content: "<meter>"; }
meter::after { content: "</meter>"; }
multicol::before { content: "<multicol>"; }
multicol::after { content: "</multicol>"; }
nav::before { content: "<nav>"; }
nav::after { content: "</nav>"; }
nextid::before { content: "<nextid>"; }
nextid::after { content: "</nextid>"; }
nobr::before { content: "<nobr>"; }
nobr::after { content: "</nobr>"; }
noembed::before { content: "<noembed>"; }
noembed::after { content: "</noembed>"; }
noframes::before { content: "<noframes>"; }
noframes::after { content: "</noframes>"; }
noscript::before { content: "<noscript>"; }
noscript::after { content: "</noscript>"; }
object::before { content: "<object>"; }
object::after { content: "</object>"; }
ol::before { content: "<ol>"; }
ol::after { content: "</ol>"; }
optgroup::before { content: "<optgroup>"; }
optgroup::after { content: "</optgroup>"; }
option::before { content: "<option>"; }
option::after { content: "</option>"; }
output::before { content: "<output>"; }
output::after { content: "</output>"; }
p::before { content: "<p>"; }
p::after { content: "</p>"; }
param::before { content: "<param>"; }
param::after { content: "</param>"; }
picture::before { content: "<picture>"; }
picture::after { content: "</picture>"; }
plaintext::before { content: "<plaintext>"; }
plaintext::after { content: "</plaintext>"; }
pre::before { content: "<pre>"; }
pre::after { content: "</pre>"; }
progress::before { content: "<progress>"; }
progress::after { content: "</progress>"; }
q::before { content: "<q>"; }
q::after { content: "</q>"; }
rb::before { content: "<rb>"; }
rb::after { content: "</rb>"; }
rp::before { content: "<rp>"; }
rp::after { content: "</rp>"; }
rt::before { content: "<rt>"; }
rt::after { content: "</rt>"; }
rtc::before { content: "<rtc>"; }
rtc::after { content: "</rtc>"; }
ruby::before { content: "<ruby>"; }
ruby::after { content: "</ruby>"; }
s::before { content: "<s>"; }
s::after { content: "</s>"; }
samp::before { content: "<samp>"; }
samp::after { content: "</samp>"; }
script::before { content: "<script>"; }
script::after { content: "</script>"; }
section::before { content: "<section>"; }
section::after { content: "</section>"; }
select::before { content: "<select>"; }
select::after { content: "</select>"; }
shadow::before { content: "<shadow>"; }
shadow::after { content: "</shadow>"; }
slot::before { content: "<slot>"; }
slot::after { content: "</slot>"; }
small::before { content: "<small>"; }
small::after { content: "</small>"; }
source::before { content: "<source>"; }
source::after { content: "</source>"; }
spacer::before { content: "<spacer>"; }
spacer::after { content: "</spacer>"; }
span::before { content: "<span>"; }
span::after { content: "</span>"; }
strike::before { content: "<strike>"; }
strike::after { content: "</strike>"; }
strong::before { content: "<strong>"; }
strong::after { content: "</strong>"; }
style::before { content: "<style>"; }
style::after { content: "<\/style>"; }
sub::before { content: "<sub>"; }
sub::after { content: "</sub>"; }
summary::before { content: "<summary>"; }
summary::after { content: "</summary>"; }
sup::before { content: "<sup>"; }
sup::after { content: "</sup>"; }
table::before { content: "<table>"; }
table::after { content: "</table>"; }
tbody::before { content: "<tbody>"; }
tbody::after { content: "</tbody>"; }
td::before { content: "<td>"; }
td::after { content: "</td>"; }
template::before { content: "<template>"; }
template::after { content: "</template>"; }
textarea::before { content: "<textarea>"; }
textarea::after { content: "</textarea>"; }
tfoot::before { content: "<tfoot>"; }
tfoot::after { content: "</tfoot>"; }
th::before { content: "<th>"; }
th::after { content: "</th>"; }
thead::before { content: "<thead>"; }
thead::after { content: "</thead>"; }
time::before { content: "<time>"; }
time::after { content: "</time>"; }
title::before { content: "<title>"; }
title::after { content: "</title>"; }
tr::before { content: "<tr>"; }
tr::after { content: "</tr>"; }
track::before { content: "<track>"; }
track::after { content: "</track>"; }
tt::before { content: "<tt>"; }
tt::after { content: "</tt>"; }
u::before { content: "<u>"; }
u::after { content: "</u>"; }
ul::before { content: "<ul>"; }
ul::after { content: "</ul>"; }
var::before { content: "<var>"; }
var::after { content: "</var>"; }
video::before { content: "<video>"; }
video::after { content: "</video>"; }
wbr::before { content: "<wbr>"; }
wbr::after { content: "</wbr>"; }
xmp::before { content: "<xmp>"; }
xmp::after { content: "</xmp>"; }

View file

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,70 @@
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(/pagetop/fonts/nunito/cyrillic_ext_400.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(/pagetop/fonts/nunito/cyrillic_400.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(/pagetop/fonts/nunito/vietnamese_400.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(/pagetop/fonts/nunito/latin_ext_400.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url(/pagetop/fonts/nunito/latin_400.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: url(/pagetop/fonts/nunito/cyrillic_ext_700.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: url(/pagetop/fonts/nunito/cyrillic_700.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: url(/pagetop/fonts/nunito/vietnamese_700.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: url(/pagetop/fonts/nunito/latin_ext_700.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 700;
src: url(/pagetop/fonts/nunito/latin_700.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,5 @@
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

@ -0,0 +1,5 @@
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

@ -0,0 +1,82 @@
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) -> &str {
"Bootsier"
}
fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) {
cfg.service(actix_web_static_files::ResourceFiles::new(
"/bootsier",
generate()
));
}
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"
)
.with_weight(-99)
)
.add_javascript(
JavaScript::source(
"/bootsier/js/bootstrap.bundle.min.js"
)
.with_weight(-98)
)
.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 +1,3 @@
pub mod aliner;
pub mod minimal;
pub mod bootsier;

View file

@ -109,7 +109,7 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]*,
"app.name" => "PageTop Application",
"app.description" => "Developed with the amazing PageTop framework.",
"app.language" => "en-US",
"app.theme" => "Minimal",
"app.theme" => "Bootsier",
"app.startup_banner" => "Small",
// [log]

View file

@ -176,6 +176,7 @@ pub struct Assets {
metadata : Vec<(String, String)>,
stylesheets: Vec<StyleSheet>,
javascripts: Vec<JavaScript>,
with_jquery: bool,
seqid_count: u16,
}
@ -186,6 +187,7 @@ impl Assets {
metadata : Vec::new(),
stylesheets: Vec::new(),
javascripts: Vec::new(),
with_jquery: false,
seqid_count: 0,
}
}
@ -222,6 +224,20 @@ impl Assets {
self
}
pub fn add_jquery(&mut self) -> &mut Self {
if !self.with_jquery {
self.add_javascript(
JavaScript::source(
"/assets/js/jquery.min.js?ver=3.6.0"
)
.with_weight(i8::MIN)
.with_mode(JSMode::Normal)
);
self.with_jquery = true;
}
self
}
pub fn render(&mut self) -> Markup {
let ordered_css = &mut self.stylesheets;
ordered_css.sort_by_key(|o| o.weight);

View file

@ -1,5 +1,5 @@
pub use actix_web::{
App, HttpRequest, HttpResponse, HttpServer, Responder, Result, web
App, HttpRequest, HttpResponse, HttpServer, Responder, Result, http, web
};
mod main;

View file

@ -14,7 +14,9 @@ use std::collections::HashMap;
pub static THEMES: Lazy<RwLock<Vec<&dyn Theme>>> = Lazy::new(|| {
RwLock::new(vec![
&base::theme::aliner::AlinerTheme,
&base::theme::minimal::MinimalTheme,
&base::theme::bootsier::BootsierTheme,
])
});
@ -24,7 +26,7 @@ pub static THEME: Lazy<&dyn Theme> = Lazy::new(|| {
return *t;
}
}
&base::theme::minimal::MinimalTheme
&base::theme::bootsier::BootsierTheme
});
pub fn register_theme(t: &'static (dyn Theme + 'static)) {

View file

@ -1,6 +1,7 @@
use crate::core::server;
use crate::core::theme::{Markup, html};
use crate::core::response::page::{Page, PageAssets, PageComponent};
use crate::base::component::Chunck;
/// Los temas deben implementar este "trait".
pub trait Theme: Send + Sync {
@ -81,4 +82,15 @@ pub trait Theme: Send + Sync {
}
*/
}
fn render_error_page(&self, s: server::http::StatusCode) -> server::Result<Markup> {
Page::prepare()
.with_title(format!("Error {}", s.as_str()).as_str())
.add_to("content", Chunck::markup(html! {
div {
h1 { (s) }
}
}))
.render()
}
}