🎨 Mejora la página de bienvenida y el tema básico #6
|
@ -3,5 +3,8 @@
|
|||
mod html;
|
||||
pub use html::Html;
|
||||
|
||||
mod block;
|
||||
pub use block::Block;
|
||||
|
||||
mod poweredby;
|
||||
pub use poweredby::PoweredBy;
|
||||
|
|
103
src/base/component/block.rs
Normal file
|
@ -0,0 +1,103 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
/// Componente genérico que representa un bloque de contenido.
|
||||
///
|
||||
/// Los bloques se utilizan como contenedores de otros componentes o contenidos, con un título
|
||||
/// opcional y un cuerpo que sólo se renderiza si existen componentes hijos (*children*).
|
||||
#[rustfmt::skip]
|
||||
#[derive(AutoDefault)]
|
||||
pub struct Block {
|
||||
id : AttrId,
|
||||
classes : AttrClasses,
|
||||
title : L10n,
|
||||
children: Children,
|
||||
}
|
||||
|
||||
impl Component for Block {
|
||||
fn new() -> Self {
|
||||
Block::default()
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<String> {
|
||||
self.id.get()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, _cx: &mut Context) {
|
||||
self.alter_classes(ClassesOp::Prepend, "block");
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
let block_body = self.children().render(cx);
|
||||
|
||||
if block_body.is_empty() {
|
||||
return PrepareMarkup::None;
|
||||
}
|
||||
|
||||
let id = cx.required_id::<Block>(self.id());
|
||||
|
||||
PrepareMarkup::With(html! {
|
||||
div id=(id) class=[self.classes().get()] {
|
||||
@if let Some(title) = self.title().lookup(cx) {
|
||||
h2 class="block__title" { span { (title) } }
|
||||
}
|
||||
div class="block__body" { (block_body) }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Block {
|
||||
// Block BUILDER *******************************************************************************
|
||||
|
||||
/// Establece el identificador único (`id`) del bloque.
|
||||
#[builder_fn]
|
||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Modifica la lista de clases CSS aplicadas al bloque.
|
||||
#[builder_fn]
|
||||
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
|
||||
self.classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el título del bloque.
|
||||
#[builder_fn]
|
||||
pub fn with_title(mut self, title: L10n) -> Self {
|
||||
self.title = title;
|
||||
self
|
||||
}
|
||||
|
||||
/// Añade un nuevo componente hijo al bloque.
|
||||
pub fn add_component(mut self, component: impl Component) -> Self {
|
||||
self.children
|
||||
.alter_child(ChildOp::Add(Child::with(component)));
|
||||
self
|
||||
}
|
||||
|
||||
/// Modifica la lista de hijos (`children`) aplicando una operación.
|
||||
#[builder_fn]
|
||||
pub fn with_child(mut self, op: ChildOp) -> Self {
|
||||
self.children.alter_child(op);
|
||||
self
|
||||
}
|
||||
|
||||
// Block GETTERS *******************************************************************************
|
||||
|
||||
/// Devuelve las clases CSS asociadas al bloque.
|
||||
pub fn classes(&self) -> &AttrClasses {
|
||||
&self.classes
|
||||
}
|
||||
|
||||
/// Devuelve el título del bloque como [`L10n`].
|
||||
pub fn title(&self) -> &L10n {
|
||||
&self.title
|
||||
}
|
||||
|
||||
/// Devuelve la lista de hijos (`children`) del bloque.
|
||||
pub fn children(&self) -> &Children {
|
||||
&self.children
|
||||
}
|
||||
}
|
|
@ -25,95 +25,26 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
|
|||
let app = &global::SETTINGS.app.name;
|
||||
|
||||
Page::new(Some(request))
|
||||
.with_title(L10n::l("welcome_page"))
|
||||
.with_theme("Basic")
|
||||
.with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/welcome.css")))
|
||||
.with_body_classes(ClassesOp::Add, "welcome")
|
||||
.with_component_in("header", Html::with(move |cx| html! {
|
||||
div class="welcome-header" {
|
||||
header class="welcome-header__body" {
|
||||
h1
|
||||
class="welcome-header__title"
|
||||
aria-label=(L10n::l("welcome_aria").with_arg("app", app).to_markup(cx))
|
||||
{
|
||||
span { (L10n::l("welcome_title").to_markup(cx)) }
|
||||
(L10n::l("welcome_intro").with_arg("app", app).to_markup(cx))
|
||||
}
|
||||
}
|
||||
aside class="welcome-header__image" aria-hidden="true" {
|
||||
div class="welcome-header__monster" {
|
||||
picture {
|
||||
source
|
||||
type="image/avif"
|
||||
src="/img/monster-pagetop_250.avif"
|
||||
srcset="/img/monster-pagetop_500.avif 1.5x";
|
||||
source
|
||||
type="image/webp"
|
||||
src="/img/monster-pagetop_250.webp"
|
||||
srcset="/img/monster-pagetop_500.webp 1.5x";
|
||||
img
|
||||
src="/img/monster-pagetop_250.png"
|
||||
srcset="/img/monster-pagetop_500.png 1.5x"
|
||||
alt="Monster PageTop";
|
||||
}
|
||||
}
|
||||
}
|
||||
.with_theme("basic")
|
||||
.with_layout("intro")
|
||||
.with_title(L10n::l("welcome_title"))
|
||||
.with_description(L10n::l("welcome_intro").with_arg("app", app))
|
||||
.add_component(Html::with(|cx| {
|
||||
html! {
|
||||
p { (L10n::l("welcome_text1").using(cx)) }
|
||||
p { (L10n::l("welcome_text2").using(cx)) }
|
||||
}
|
||||
}))
|
||||
.with_component(Html::with(move |cx| html! {
|
||||
main class="welcome-content" {
|
||||
section class="welcome-content__body" {
|
||||
div class="welcome-poweredby" {
|
||||
a
|
||||
class="welcome-poweredby__link"
|
||||
href="https://pagetop.cillero.es"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
{
|
||||
span {} span {} span {}
|
||||
div class="welcome-poweredby__text" {
|
||||
(L10n::l("welcome_powered").to_markup(cx))
|
||||
}
|
||||
}
|
||||
.add_component(
|
||||
Block::new()
|
||||
.with_title(L10n::l("welcome_about"))
|
||||
.add_component(Html::with(move |cx| {
|
||||
html! {
|
||||
p { (L10n::l("welcome_pagetop").using(cx)) }
|
||||
p { (L10n::l("welcome_issues1").using(cx)) }
|
||||
p { (L10n::l("welcome_issues2").with_arg("app", app).using(cx)) }
|
||||
}
|
||||
div class="welcome-text" {
|
||||
p { (L10n::l("welcome_text1").to_markup(cx)) }
|
||||
p { (L10n::l("welcome_text2").to_markup(cx)) }
|
||||
|
||||
div class="welcome-text__block" {
|
||||
h2 { span { (L10n::l("welcome_about").to_markup(cx)) } }
|
||||
p { (L10n::l("welcome_pagetop").to_markup(cx)) }
|
||||
p { (L10n::l("welcome_issues1").to_markup(cx)) }
|
||||
p { (L10n::l("welcome_issues2").with_arg("app", app).to_markup(cx)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
.with_component_in("footer", Html::with(move |cx| html! {
|
||||
section class="welcome-footer" {
|
||||
div class="welcome-footer__logo" {
|
||||
svg
|
||||
viewBox="0 0 1614 1614"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
role="img"
|
||||
aria-label=[L10n::l("pagetop_logo").using(cx)]
|
||||
preserveAspectRatio="xMidYMid slice"
|
||||
focusable="false"
|
||||
{
|
||||
path fill="rgb(255,255,255)" d="M 1573,357 L 1415,357 C 1400,357 1388,369 1388,383 L 1388,410 1335,410 1335,357 C 1335,167 1181,13 992,13 L 621,13 C 432,13 278,167 278,357 L 278,410 225,410 225,383 C 225,369 213,357 198,357 L 40,357 C 25,357 13,369 13,383 L 13,648 C 13,662 25,674 40,674 L 198,674 C 213,674 225,662 225,648 L 225,621 278,621 278,1256 C 278,1446 432,1600 621,1600 L 992,1600 C 1181,1600 1335,1446 1335,1256 L 1335,621 1388,621 1388,648 C 1388,662 1400,674 1415,674 L 1573,674 C 1588,674 1600,662 1600,648 L 1600,383 C 1600,369 1588,357 1573,357 L 1573,357 1573,357 Z M 66,410 L 172,410 172,621 66,621 66,410 66,410 Z M 1282,357 L 1282,488 C 1247,485 1213,477 1181,464 L 1196,437 C 1203,425 1199,409 1186,401 1174,394 1158,398 1150,411 L 1133,440 C 1105,423 1079,401 1056,376 L 1075,361 C 1087,352 1089,335 1079,324 1070,313 1054,311 1042,320 L 1023,335 C 1000,301 981,263 967,221 L 1011,196 C 1023,189 1028,172 1021,160 1013,147 997,143 984,150 L 953,168 C 945,136 941,102 940,66 L 992,66 C 1152,66 1282,197 1282,357 L 1282,357 1282,357 Z M 621,66 L 674,66 674,225 648,225 C 633,225 621,237 621,251 621,266 633,278 648,278 L 674,278 674,357 648,357 C 633,357 621,369 621,383 621,398 633,410 648,410 L 674,410 674,489 648,489 C 633,489 621,501 621,516 621,530 633,542 648,542 L 664,542 C 651,582 626,623 600,662 583,653 563,648 542,648 469,648 410,707 410,780 410,787 411,794 412,801 388,805 361,806 331,806 L 331,357 C 331,197 461,66 621,66 L 621,66 621,66 Z M 621,780 C 621,824 586,859 542,859 498,859 463,824 463,780 463,736 498,701 542,701 586,701 621,736 621,780 L 621,780 621,780 Z M 225,463 L 278,463 278,569 225,569 225,463 225,463 Z M 992,1547 L 621,1547 C 461,1547 331,1416 331,1256 L 331,859 C 367,859 400,858 431,851 454,888 495,912 542,912 615,912 674,853 674,780 674,747 662,718 642,695 675,645 706,594 720,542 L 780,542 C 795,542 807,530 807,516 807,501 795,489 780,489 L 727,489 727,410 780,410 C 795,410 807,398 807,383 807,369 795,357 780,357 L 727,357 727,278 780,278 C 795,278 807,266 807,251 807,237 795,225 780,225 L 727,225 727,66 887,66 C 889,111 895,155 905,196 L 869,217 C 856,224 852,240 859,253 864,261 873,266 882,266 887,266 891,265 895,263 L 921,248 C 937,291 958,331 983,367 L 938,403 C 926,412 925,429 934,440 939,447 947,450 954,450 960,450 966,448 971,444 L 1016,408 C 1043,438 1074,465 1108,485 L 1084,527 C 1076,539 1081,555 1093,563 1098,565 1102,566 1107,566 1116,566 1125,561 1129,553 L 1155,509 C 1194,527 1237,538 1282,541 L 1282,1256 C 1282,1416 1152,1547 992,1547 L 992,1547 992,1547 Z M 1335,463 L 1388,463 1388,569 1335,569 1335,463 1335,463 Z M 1441,410 L 1547,410 1547,621 1441,621 1441,410 1441,410 Z" {}
|
||||
path fill="rgb(255,255,255)" d="M 1150,1018 L 463,1018 C 448,1018 436,1030 436,1044 L 436,1177 C 436,1348 545,1468 701,1468 L 912,1468 C 1068,1468 1177,1348 1177,1177 L 1177,1044 C 1177,1030 1165,1018 1150,1018 L 1150,1018 1150,1018 Z M 912,1071 L 1018,1071 1018,1124 912,1124 912,1071 912,1071 Z M 489,1071 L 542,1071 542,1124 489,1124 489,1071 489,1071 Z M 701,1415 L 700,1415 C 701,1385 704,1352 718,1343 731,1335 759,1341 795,1359 802,1363 811,1363 818,1359 854,1341 882,1335 895,1343 909,1352 912,1385 913,1415 L 912,1415 701,1415 701,1415 701,1415 Z M 1124,1177 C 1124,1296 1061,1384 966,1408 964,1365 958,1320 922,1298 894,1281 856,1283 807,1306 757,1283 719,1281 691,1298 655,1320 649,1365 647,1408 552,1384 489,1296 489,1177 L 569,1177 C 583,1177 595,1165 595,1150 L 595,1071 859,1071 859,1150 C 859,1165 871,1177 886,1177 L 1044,1177 C 1059,1177 1071,1165 1071,1150 L 1071,1071 1124,1071 1124,1177 1124,1177 1124,1177 Z" {}
|
||||
path fill="rgb(255,255,255)" d="M 1071,648 C 998,648 939,707 939,780 939,853 998,912 1071,912 1144,912 1203,853 1203,780 1203,707 1144,648 1071,648 L 1071,648 1071,648 Z M 1071,859 C 1027,859 992,824 992,780 992,736 1027,701 1071,701 1115,701 1150,736 1150,780 1150,824 1115,859 1071,859 L 1071,859 1071,859 Z" {}
|
||||
}
|
||||
}
|
||||
div class="welcome-footer__links" {
|
||||
a href="https://crates.io/crates/pagetop" target="_blank" rel="noreferrer" { ("Crates.io") }
|
||||
a href="https://docs.rs/pagetop" target="_blank" rel="noreferrer" { ("Docs.rs") }
|
||||
a href="https://git.cillero.es/manuelcillero/pagetop" target="_blank" rel="noreferrer" { (L10n::l("welcome_code").to_markup(cx)) }
|
||||
em { (L10n::l("welcome_have_fun").to_markup(cx)) }
|
||||
}
|
||||
}
|
||||
}))
|
||||
.with_component_in("footer", PoweredBy::new())
|
||||
})),
|
||||
)
|
||||
.render()
|
||||
}
|
||||
|
|
|
@ -12,16 +12,105 @@ impl Extension for Basic {
|
|||
}
|
||||
|
||||
impl Theme for Basic {
|
||||
fn render_page_body(&self, page: &mut Page) -> Markup {
|
||||
match page.layout() {
|
||||
"intro" => render_intro(page),
|
||||
_ => <Self as ThemePage>::render_body(self, page, self.page_regions()),
|
||||
}
|
||||
}
|
||||
|
||||
fn after_render_page_body(&self, page: &mut Page) {
|
||||
let styles = match page.layout() {
|
||||
"intro" => "/css/intro.css",
|
||||
_ => "/css/basic.css",
|
||||
};
|
||||
page.alter_assets(AssetsOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/normalize.css")
|
||||
.with_version("8.0.1")
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_assets(AssetsOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/basic.css")
|
||||
StyleSheet::from(styles)
|
||||
.with_version(env!("CARGO_PKG_VERSION"))
|
||||
.with_weight(-99),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn render_intro(page: &mut Page) -> Markup {
|
||||
let title = page.title().unwrap_or_default();
|
||||
let intro = page.description().unwrap_or_default();
|
||||
|
||||
html! {
|
||||
body id=[page.body_id().get()] class=[page.body_classes().get()] {
|
||||
header class="intro-header" {
|
||||
section class="intro-header__body" {
|
||||
h1 class="intro-header__title" {
|
||||
span { (title) }
|
||||
(intro)
|
||||
}
|
||||
}
|
||||
aside class="intro-header__image" aria-hidden="true" {
|
||||
div class="intro-header__monster" {
|
||||
picture {
|
||||
source
|
||||
type="image/avif"
|
||||
src="/img/monster-pagetop_250.avif"
|
||||
srcset="/img/monster-pagetop_500.avif 1.5x";
|
||||
source
|
||||
type="image/webp"
|
||||
src="/img/monster-pagetop_250.webp"
|
||||
srcset="/img/monster-pagetop_500.webp 1.5x";
|
||||
img
|
||||
src="/img/monster-pagetop_250.png"
|
||||
srcset="/img/monster-pagetop_500.png 1.5x"
|
||||
alt="Monster PageTop";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
main class="intro-content" {
|
||||
section class="intro-content__body" {
|
||||
div class="intro-button" {
|
||||
a
|
||||
class="intro-button__link"
|
||||
href="https://pagetop.cillero.es"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
{
|
||||
span {} span {} span {}
|
||||
div class="intro-button__text" {
|
||||
(L10n::l("welcome_powered").using(page))
|
||||
}
|
||||
}
|
||||
}
|
||||
div class="intro-text" { (page.render_region("content")) }
|
||||
}
|
||||
}
|
||||
footer class="intro-footer" {
|
||||
section class="intro-footer__body" {
|
||||
div class="intro-footer__logo" {
|
||||
svg
|
||||
viewBox="0 0 1614 1614"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
role="img"
|
||||
aria-label=[L10n::l("pagetop_logo").lookup(page)]
|
||||
preserveAspectRatio="xMidYMid slice"
|
||||
focusable="false"
|
||||
{
|
||||
path fill="rgb(255,255,255)" d="M 1573,357 L 1415,357 C 1400,357 1388,369 1388,383 L 1388,410 1335,410 1335,357 C 1335,167 1181,13 992,13 L 621,13 C 432,13 278,167 278,357 L 278,410 225,410 225,383 C 225,369 213,357 198,357 L 40,357 C 25,357 13,369 13,383 L 13,648 C 13,662 25,674 40,674 L 198,674 C 213,674 225,662 225,648 L 225,621 278,621 278,1256 C 278,1446 432,1600 621,1600 L 992,1600 C 1181,1600 1335,1446 1335,1256 L 1335,621 1388,621 1388,648 C 1388,662 1400,674 1415,674 L 1573,674 C 1588,674 1600,662 1600,648 L 1600,383 C 1600,369 1588,357 1573,357 L 1573,357 1573,357 Z M 66,410 L 172,410 172,621 66,621 66,410 66,410 Z M 1282,357 L 1282,488 C 1247,485 1213,477 1181,464 L 1196,437 C 1203,425 1199,409 1186,401 1174,394 1158,398 1150,411 L 1133,440 C 1105,423 1079,401 1056,376 L 1075,361 C 1087,352 1089,335 1079,324 1070,313 1054,311 1042,320 L 1023,335 C 1000,301 981,263 967,221 L 1011,196 C 1023,189 1028,172 1021,160 1013,147 997,143 984,150 L 953,168 C 945,136 941,102 940,66 L 992,66 C 1152,66 1282,197 1282,357 L 1282,357 1282,357 Z M 621,66 L 674,66 674,225 648,225 C 633,225 621,237 621,251 621,266 633,278 648,278 L 674,278 674,357 648,357 C 633,357 621,369 621,383 621,398 633,410 648,410 L 674,410 674,489 648,489 C 633,489 621,501 621,516 621,530 633,542 648,542 L 664,542 C 651,582 626,623 600,662 583,653 563,648 542,648 469,648 410,707 410,780 410,787 411,794 412,801 388,805 361,806 331,806 L 331,357 C 331,197 461,66 621,66 L 621,66 621,66 Z M 621,780 C 621,824 586,859 542,859 498,859 463,824 463,780 463,736 498,701 542,701 586,701 621,736 621,780 L 621,780 621,780 Z M 225,463 L 278,463 278,569 225,569 225,463 225,463 Z M 992,1547 L 621,1547 C 461,1547 331,1416 331,1256 L 331,859 C 367,859 400,858 431,851 454,888 495,912 542,912 615,912 674,853 674,780 674,747 662,718 642,695 675,645 706,594 720,542 L 780,542 C 795,542 807,530 807,516 807,501 795,489 780,489 L 727,489 727,410 780,410 C 795,410 807,398 807,383 807,369 795,357 780,357 L 727,357 727,278 780,278 C 795,278 807,266 807,251 807,237 795,225 780,225 L 727,225 727,66 887,66 C 889,111 895,155 905,196 L 869,217 C 856,224 852,240 859,253 864,261 873,266 882,266 887,266 891,265 895,263 L 921,248 C 937,291 958,331 983,367 L 938,403 C 926,412 925,429 934,440 939,447 947,450 954,450 960,450 966,448 971,444 L 1016,408 C 1043,438 1074,465 1108,485 L 1084,527 C 1076,539 1081,555 1093,563 1098,565 1102,566 1107,566 1116,566 1125,561 1129,553 L 1155,509 C 1194,527 1237,538 1282,541 L 1282,1256 C 1282,1416 1152,1547 992,1547 L 992,1547 992,1547 Z M 1335,463 L 1388,463 1388,569 1335,569 1335,463 1335,463 Z M 1441,410 L 1547,410 1547,621 1441,621 1441,410 1441,410 Z" {}
|
||||
path fill="rgb(255,255,255)" d="M 1150,1018 L 463,1018 C 448,1018 436,1030 436,1044 L 436,1177 C 436,1348 545,1468 701,1468 L 912,1468 C 1068,1468 1177,1348 1177,1177 L 1177,1044 C 1177,1030 1165,1018 1150,1018 L 1150,1018 1150,1018 Z M 912,1071 L 1018,1071 1018,1124 912,1124 912,1071 912,1071 Z M 489,1071 L 542,1071 542,1124 489,1124 489,1071 489,1071 Z M 701,1415 L 700,1415 C 701,1385 704,1352 718,1343 731,1335 759,1341 795,1359 802,1363 811,1363 818,1359 854,1341 882,1335 895,1343 909,1352 912,1385 913,1415 L 912,1415 701,1415 701,1415 701,1415 Z M 1124,1177 C 1124,1296 1061,1384 966,1408 964,1365 958,1320 922,1298 894,1281 856,1283 807,1306 757,1283 719,1281 691,1298 655,1320 649,1365 647,1408 552,1384 489,1296 489,1177 L 569,1177 C 583,1177 595,1165 595,1150 L 595,1071 859,1071 859,1150 C 859,1165 871,1177 886,1177 L 1044,1177 C 1059,1177 1071,1165 1071,1150 L 1071,1071 1124,1071 1124,1177 1124,1177 1124,1177 Z" {}
|
||||
path fill="rgb(255,255,255)" d="M 1071,648 C 998,648 939,707 939,780 939,853 998,912 1071,912 1144,912 1203,853 1203,780 1203,707 1144,648 1071,648 L 1071,648 1071,648 Z M 1071,859 C 1027,859 992,824 992,780 992,736 1027,701 1071,701 1115,701 1150,736 1150,780 1150,824 1115,859 1071,859 L 1071,859 1071,859 Z" {}
|
||||
}
|
||||
}
|
||||
div class="intro-footer__links" {
|
||||
a href="https://crates.io/crates/pagetop" target="_blank" rel="noreferrer" { ("Crates.io") }
|
||||
a href="https://docs.rs/pagetop" target="_blank" rel="noreferrer" { ("Docs.rs") }
|
||||
a href="https://git.cillero.es/manuelcillero/pagetop" target="_blank" rel="noreferrer" { (L10n::l("welcome_code").using(page)) }
|
||||
em { (L10n::l("welcome_have_fun").using(page)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,14 +29,14 @@ pub trait Component: AnyInfo + ComponentRender + Send + Sync {
|
|||
TypeInfo::ShortName.of::<Self>()
|
||||
}
|
||||
|
||||
/// Devuelve una descripción opcional del componente.
|
||||
/// Devuelve una descripción del componente, si existe.
|
||||
///
|
||||
/// Por defecto, no se proporciona ninguna descripción (`None`).
|
||||
fn description(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Devuelve un identificador opcional para el componente.
|
||||
/// Devuelve el identificador del componente, si existe.
|
||||
///
|
||||
/// Este identificador puede usarse para referenciar el componente en el HTML. Por defecto, no
|
||||
/// tiene ningún identificador (`None`).
|
||||
|
@ -51,7 +51,7 @@ pub trait Component: AnyInfo + ComponentRender + Send + Sync {
|
|||
#[allow(unused_variables)]
|
||||
fn setup_before_prepare(&mut self, cx: &mut Context) {}
|
||||
|
||||
/// Devuelve una representación estructurada del componente preparada para el renderizado.
|
||||
/// Devuelve una representación renderizada del componente.
|
||||
///
|
||||
/// Este método forma parte del ciclo de vida de los componentes y se invoca automáticamente
|
||||
/// durante el proceso de construcción del documento. Puede sobrescribirse para generar
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
//! [`Theme`].
|
||||
|
||||
mod definition;
|
||||
pub use definition::{Theme, ThemeRef};
|
||||
pub use definition::{Theme, ThemePage, ThemeRef};
|
||||
|
||||
mod regions;
|
||||
pub(crate) use regions::ChildrenInRegions;
|
||||
pub use regions::{InRegion, Region, REGION_CONTENT};
|
||||
pub(crate) use regions::{ChildrenInRegions, REGION_CONTENT};
|
||||
pub use regions::{InRegion, Region};
|
||||
|
||||
pub(crate) mod all;
|
||||
|
|
|
@ -7,88 +7,34 @@ use crate::response::page::Page;
|
|||
|
||||
use std::sync::LazyLock;
|
||||
|
||||
/// Representa una referencia a un tema.
|
||||
/// Referencia estática a un tema.
|
||||
///
|
||||
/// Los temas son también extensiones. Por tanto se deben definir igual, es decir, como instancias
|
||||
/// estáticas globales que implementan [`Theme`], pero también [`Extension`].
|
||||
/// Los temas son también extensiones. Por tanto, deben declararse como **instancias estáticas** que
|
||||
/// implementen [`Theme`] y, a su vez, [`Extension`].
|
||||
pub type ThemeRef = &'static dyn Theme;
|
||||
|
||||
/// Interfaz común que debe implementar cualquier tema de `PageTop`.
|
||||
/// Métodos predefinidos de renderizado para las páginas de un tema.
|
||||
///
|
||||
/// Un tema implementará [`Theme`] y los métodos que sean necesarios de [`Extension`], aunque el
|
||||
/// único obligatorio será [`theme()`](Extension::theme).
|
||||
/// Contiene las implementaciones base de las **secciones** `<head>` y `<body>`. Se implementa
|
||||
/// automáticamente para cualquier tipo que implemente [`Theme`], por lo que normalmente no requiere
|
||||
/// implementación explícita.
|
||||
///
|
||||
/// ```rust
|
||||
/// use pagetop::prelude::*;
|
||||
/// Si un tema **sobrescribe** [`render_page_head()`](Theme::render_page_head) o
|
||||
/// [`render_page_body()`](Theme::render_page_body), se puede volver al comportamiento por defecto
|
||||
/// cuando se necesite usando FQS (*Fully Qualified Syntax*):
|
||||
///
|
||||
/// pub struct MyTheme;
|
||||
///
|
||||
/// impl Extension for MyTheme {
|
||||
/// fn name(&self) -> L10n {
|
||||
/// L10n::n("My theme")
|
||||
/// }
|
||||
///
|
||||
/// fn description(&self) -> L10n {
|
||||
/// L10n::n("A personal theme")
|
||||
/// }
|
||||
///
|
||||
/// fn theme(&self) -> Option<ThemeRef> {
|
||||
/// Some(&Self)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl Theme for MyTheme {}
|
||||
/// ```
|
||||
pub trait Theme: Extension + Send + Sync {
|
||||
/// **Obsoleto desde la versión 0.4.0**: usar [`declared_regions()`](Self::declared_regions) en
|
||||
/// su lugar.
|
||||
#[deprecated(since = "0.4.0", note = "Use `declared_regions()` instead")]
|
||||
fn regions(&self) -> Vec<(&'static str, L10n)> {
|
||||
vec![("content", L10n::l("content"))]
|
||||
}
|
||||
|
||||
/// Declaración ordenada de las regiones disponibles en la página.
|
||||
///
|
||||
/// Devuelve una lista estática de pares `(Region, L10n)` que se usará para renderizar en el
|
||||
/// orden indicado todas las regiones que componen una página. Los identificadores deben ser
|
||||
/// **estables** como `"sidebar-left"` o `"content"`. La etiqueta `L10n` devuelve el nombre de la
|
||||
/// región en el idioma activo de la página.
|
||||
///
|
||||
/// Si el tema requiere un conjunto distinto de regiones, se puede sobrescribir este método para
|
||||
/// devolver una lista diferente. Si no, se usará la lista predeterminada:
|
||||
///
|
||||
/// - `"header"`: cabecera.
|
||||
/// - `"content"`: contenido principal (**obligatoria**).
|
||||
/// - `"footer"`: pie.
|
||||
///
|
||||
/// Sólo la región `"content"` es obligatoria, usa [`Region::default()`] para declararla.
|
||||
#[inline]
|
||||
fn declared_regions(&self) -> &'static [(Region, L10n)] {
|
||||
static REGIONS: LazyLock<[(Region, L10n); 3]> = LazyLock::new(|| {
|
||||
[
|
||||
(Region::declare("header"), L10n::l("region_header")),
|
||||
(Region::default(), L10n::l("region_content")),
|
||||
(Region::declare("footer"), L10n::l("region_footer")),
|
||||
]
|
||||
});
|
||||
®IONS[..]
|
||||
}
|
||||
|
||||
/// Acciones específicas del tema antes de renderizar el `<body>` de la página.
|
||||
///
|
||||
/// Útil para preparar clases, inyectar recursos o ajustar metadatos.
|
||||
#[allow(unused_variables)]
|
||||
fn before_render_page_body(&self, page: &mut Page) {}
|
||||
|
||||
/// - `<Self as ThemePage>::render_body(self, page, self.page_regions())`
|
||||
/// - `<Self as ThemePage>::render_head(self, page)`
|
||||
pub trait ThemePage {
|
||||
/// Renderiza el contenido del `<body>` de la página.
|
||||
///
|
||||
/// Por defecto, recorre [`declared_regions()`](Self::declared_regions) **en el orden que se han
|
||||
/// declarado** y, para cada región con contenido, genera un contenedor con `role="region"` y
|
||||
/// `aria-label` localizado.
|
||||
fn render_page_body(&self, page: &mut Page) -> Markup {
|
||||
/// Recorre `regions` en el **orden declarado** y, para cada región con contenido, genera un
|
||||
/// contenedor con `role="region"` y un `aria-label` localizado. Se asume que cada identificador
|
||||
/// de región es **único** dentro de la página.
|
||||
fn render_body(&self, page: &mut Page, regions: &[(Region, L10n)]) -> Markup {
|
||||
html! {
|
||||
body id=[page.body_id().get()] class=[page.body_classes().get()] {
|
||||
@for (region, region_label) in self.declared_regions() {
|
||||
@for (region, region_label) in regions {
|
||||
@let output = page.render_region(region.key());
|
||||
@if !output.is_empty() {
|
||||
@let region_name = region.name();
|
||||
|
@ -96,7 +42,7 @@ pub trait Theme: Extension + Send + Sync {
|
|||
id=(region_name)
|
||||
class={ "region region--" (region_name) }
|
||||
role="region"
|
||||
aria-label=[region_label.using(page)]
|
||||
aria-label=[region_label.lookup(page)]
|
||||
{
|
||||
(output)
|
||||
}
|
||||
|
@ -106,17 +52,12 @@ pub trait Theme: Extension + Send + Sync {
|
|||
}
|
||||
}
|
||||
|
||||
/// Acciones específicas del tema después de renderizar el `<body>` de la página.
|
||||
///
|
||||
/// Útil para *tracing*, métricas o ajustes finales del estado de la página.
|
||||
#[allow(unused_variables)]
|
||||
fn after_render_page_body(&self, page: &mut Page) {}
|
||||
|
||||
/// Renderiza el contenido del `<head>` de la página.
|
||||
///
|
||||
/// Por defecto, genera las etiquetas básicas (`charset`, `title`, `description`, `viewport`,
|
||||
/// `X-UA-Compatible`), los metadatos y propiedades de la página y los recursos (CSS/JS).
|
||||
fn render_page_head(&self, page: &mut Page) -> Markup {
|
||||
/// Por defecto incluye las etiquetas básicas (`charset`, `title`, `description`, `viewport`,
|
||||
/// `X-UA-Compatible`), los metadatos (`name/content`) y propiedades (`property/content`),
|
||||
/// además de los recursos CSS/JS de la página.
|
||||
fn render_head(&self, page: &mut Page) -> Markup {
|
||||
let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no";
|
||||
html! {
|
||||
head {
|
||||
|
@ -146,18 +87,115 @@ pub trait Theme: Extension + Send + Sync {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Página de error "*403 – Forbidden*" predeterminada.
|
||||
/// Interfaz común que debe implementar cualquier tema de PageTop.
|
||||
///
|
||||
/// Un tema implementa [`Theme`] y los métodos necesarios de [`Extension`]. El único método
|
||||
/// **obligatorio** de `Extension` para un tema es [`theme()`](Extension::theme).
|
||||
///
|
||||
/// ```rust
|
||||
/// use pagetop::prelude::*;
|
||||
///
|
||||
/// pub struct MyTheme;
|
||||
///
|
||||
/// impl Extension for MyTheme {
|
||||
/// fn name(&self) -> L10n {
|
||||
/// L10n::n("My theme")
|
||||
/// }
|
||||
///
|
||||
/// fn description(&self) -> L10n {
|
||||
/// L10n::n("A personal theme")
|
||||
/// }
|
||||
///
|
||||
/// fn theme(&self) -> Option<ThemeRef> {
|
||||
/// Some(&Self)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl Theme for MyTheme {}
|
||||
/// ```
|
||||
pub trait Theme: Extension + ThemePage + Send + Sync {
|
||||
/// **Obsoleto desde la versión 0.4.0**: usar [`page_regions()`](Self::page_regions) en su
|
||||
/// lugar.
|
||||
#[deprecated(since = "0.4.0", note = "Use `page_regions()` instead")]
|
||||
fn regions(&self) -> Vec<(&'static str, L10n)> {
|
||||
vec![("content", L10n::l("content"))]
|
||||
}
|
||||
|
||||
/// Declaración ordenada de las regiones disponibles en la página.
|
||||
///
|
||||
/// Devuelve una **lista estática** de pares `(Region, L10n)` que se usará para renderizar en el
|
||||
/// orden indicado todas las regiones que componen una página.
|
||||
///
|
||||
/// Requisitos y recomendaciones:
|
||||
///
|
||||
/// - Los identificadores deben ser **estables** (p. ej. `"sidebar-left"`, `"content"`).
|
||||
/// - La región `"content"` es **obligatoria**. Se puede usar [`Region::default()`] para
|
||||
/// declararla.
|
||||
/// - La etiqueta `L10n` se evalúa con el idioma activo de la página.
|
||||
///
|
||||
/// Si tu tema define un conjunto distinto, se puede **sobrescribir** este método. Por defecto
|
||||
/// devuelve:
|
||||
///
|
||||
/// - `"header"`: cabecera.
|
||||
/// - `"content"`: contenido principal (**obligatoria**).
|
||||
/// - `"footer"`: pie.
|
||||
fn page_regions(&self) -> &'static [(Region, L10n)] {
|
||||
static REGIONS: LazyLock<[(Region, L10n); 3]> = LazyLock::new(|| {
|
||||
[
|
||||
(Region::declare("header"), L10n::l("region_header")),
|
||||
(Region::default(), L10n::l("region_content")),
|
||||
(Region::declare("footer"), L10n::l("region_footer")),
|
||||
]
|
||||
});
|
||||
®IONS[..]
|
||||
}
|
||||
|
||||
/// Acciones específicas del tema antes de renderizar el `<body>` de la página.
|
||||
///
|
||||
/// Útil para preparar clases, inyectar recursos o ajustar metadatos.
|
||||
#[allow(unused_variables)]
|
||||
fn before_render_page_body(&self, page: &mut Page) {}
|
||||
|
||||
/// Renderiza el contenido del `<body>` de la página.
|
||||
///
|
||||
/// Si se sobrescribe este método, se puede volver al comportamiento base con:
|
||||
/// `<Self as ThemePage>::render_body(self, page, self.page_regions())`.
|
||||
#[inline]
|
||||
fn render_page_body(&self, page: &mut Page) -> Markup {
|
||||
<Self as ThemePage>::render_body(self, page, self.page_regions())
|
||||
}
|
||||
|
||||
/// Acciones específicas del tema después de renderizar el `<body>` de la página.
|
||||
///
|
||||
/// Útil para *tracing*, métricas o ajustes finales del estado de la página.
|
||||
#[allow(unused_variables)]
|
||||
fn after_render_page_body(&self, page: &mut Page) {}
|
||||
|
||||
/// Renderiza el contenido del `<head>` de la página.
|
||||
///
|
||||
/// Si se sobrescribe este método, se puede volver al comportamiento base con:
|
||||
/// `<Self as ThemePage>::render_head(self, page)`.
|
||||
#[inline]
|
||||
fn render_page_head(&self, page: &mut Page) -> Markup {
|
||||
<Self as ThemePage>::render_head(self, page)
|
||||
}
|
||||
|
||||
/// Contenido predeterminado para la página de error "*403 – Forbidden*".
|
||||
///
|
||||
/// Se puede sobrescribir este método para personalizar y adaptar este contenido al tema.
|
||||
fn error403(&self, page: &mut Page) -> Markup {
|
||||
html! { div { h1 { (L10n::l("error403_notice").to_markup(page)) } } }
|
||||
html! { div { h1 { (L10n::l("error403_notice").using(page)) } } }
|
||||
}
|
||||
|
||||
/// Página de error "*404 – Not Found*" predeterminada.
|
||||
/// Contenido predeterminado para la página de error "*404 – Not Found*".
|
||||
///
|
||||
/// Se puede sobrescribir este método para personalizar y adaptar este contenido al tema.
|
||||
fn error404(&self, page: &mut Page) -> Markup {
|
||||
html! { div { h1 { (L10n::l("error404_notice").to_markup(page)) } } }
|
||||
html! { div { h1 { (L10n::l("error404_notice").using(page)) } } }
|
||||
}
|
||||
}
|
||||
|
||||
/// Se implementa automáticamente `ThemePage` para cualquier tema.
|
||||
impl<T: Theme> ThemePage for T {}
|
||||
|
|
|
@ -25,7 +25,7 @@ pub const REGION_CONTENT: &str = "content";
|
|||
/// (p.ej., clases `region__{name}`).
|
||||
///
|
||||
/// Se utiliza para declarar las regiones que componen una página en un tema (ver
|
||||
/// [`declared_regions()`](crate::core::theme::Theme::declared_regions)).
|
||||
/// [`page_regions()`](crate::core::theme::Theme::page_regions)).
|
||||
pub struct Region {
|
||||
key: &'static str,
|
||||
name: String,
|
||||
|
|
|
@ -3,7 +3,6 @@ welcome_extension_description = Displays a landing page when none is configured.
|
|||
|
||||
welcome_page = Welcome Page
|
||||
welcome_title = Hello world!
|
||||
welcome_aria = Say hello to your { $app } installation
|
||||
|
||||
welcome_intro = Discover⚡{ $app }
|
||||
welcome_powered = A web solution powered by <strong>PageTop!</strong>
|
||||
|
|
|
@ -3,7 +3,6 @@ welcome_extension_description = Muestra una página de inicio predeterminada cua
|
|||
|
||||
welcome_page = Página de Bienvenida
|
||||
welcome_title = ¡Hola mundo!
|
||||
welcome_aria = Saluda a tu instalación { $app }
|
||||
|
||||
welcome_intro = Descubre⚡{ $app }
|
||||
welcome_powered = Una solución web creada con <strong>PageTop!</strong>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
:root {
|
||||
--bg-img: url('/img/welcome-header.jpg');
|
||||
--bg-img-set: image-set(url('/img/welcome-header.avif') type('image/avif'), url('/img/welcome-header.webp') type('image/webp'), var(--bg-img) type('image/jpeg'));
|
||||
--bg-img-sm: url('/img/welcome-header-sm.jpg');
|
||||
--bg-img-sm-set: image-set(url('/img/welcome-header-sm.avif') type('image/avif'), url('/img/welcome-header-sm.webp') type('image/webp'), var(--bg-img-sm) type('image/jpeg'));
|
||||
--bg-img: url('/img/intro-header.jpg');
|
||||
--bg-img-set: image-set(url('/img/intro-header.avif') type('image/avif'), url('/img/intro-header.webp') type('image/webp'), var(--bg-img) type('image/jpeg'));
|
||||
--bg-img-sm: url('/img/intro-header-sm.jpg');
|
||||
--bg-img-sm-set: image-set(url('/img/intro-header-sm.avif') type('image/avif'), url('/img/intro-header-sm.webp') type('image/webp'), var(--bg-img-sm) type('image/jpeg'));
|
||||
--bg-color: #8c5919;
|
||||
--color: #1a202c;
|
||||
--color-red: #fecaca;
|
||||
|
@ -28,9 +28,14 @@ body {
|
|||
font-weight: 300;
|
||||
color: var(--color);
|
||||
line-height: 1.6;
|
||||
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
header,
|
||||
section {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
@ -50,19 +55,11 @@ a:hover:visited {
|
|||
text-decoration-color: var(--color-link);
|
||||
}
|
||||
|
||||
#content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/*
|
||||
* Region header
|
||||
* Header
|
||||
*/
|
||||
|
||||
.welcome-header {
|
||||
.intro-header {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
width: 100%;
|
||||
|
@ -76,11 +73,11 @@ a:hover:visited {
|
|||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.welcome-header__body {
|
||||
.intro-header__body {
|
||||
padding: 0;
|
||||
background: none;
|
||||
}
|
||||
.welcome-header__title {
|
||||
.intro-header__title {
|
||||
margin: 0 0 0 1.5rem;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
|
@ -94,7 +91,7 @@ a:hover:visited {
|
|||
line-height: 110%;
|
||||
text-shadow: 0 0.125rem 0.1875rem rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.welcome-header__title > span {
|
||||
.intro-header__title > span {
|
||||
background: linear-gradient(180deg, #ddff95 30%, #ffb84b 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
|
@ -105,44 +102,44 @@ a:hover:visited {
|
|||
line-height: 110%;
|
||||
text-shadow: none;
|
||||
}
|
||||
.welcome-header__image {
|
||||
.intro-header__image {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
}
|
||||
.welcome-header__monster {
|
||||
.intro-header__monster {
|
||||
margin-right: 12rem;
|
||||
margin-top: 1rem;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
@media (min-width: 64rem) {
|
||||
.welcome-header {
|
||||
.intro-header {
|
||||
background-image: var(--bg-img);
|
||||
background-image: var(--bg-img-set);
|
||||
}
|
||||
.welcome-header__title {
|
||||
.intro-header__title {
|
||||
padding: 1.2rem 2rem 2.6rem 2rem;
|
||||
}
|
||||
.welcome-header__image {
|
||||
.intro-header__image {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Region content
|
||||
* Content
|
||||
*/
|
||||
|
||||
.welcome-content {
|
||||
.intro-content {
|
||||
height: auto;
|
||||
margin-top: 1.6rem;
|
||||
}
|
||||
.welcome-content__body {
|
||||
.intro-content__body {
|
||||
box-sizing: border-box;
|
||||
max-width: 80rem;
|
||||
}
|
||||
.welcome-content__body:before,
|
||||
.welcome-content__body:after {
|
||||
.intro-content__body:before,
|
||||
.intro-content__body:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
@ -152,38 +149,37 @@ a:hover:visited {
|
|||
filter: blur(2.75rem);
|
||||
opacity: 0.8;
|
||||
inset: 11.75rem;
|
||||
/*z-index: 0;*/
|
||||
}
|
||||
.welcome-content__body:before {
|
||||
.intro-content__body:before {
|
||||
top: -1rem;
|
||||
}
|
||||
.welcome-content__body:after {
|
||||
.intro-content__body:after {
|
||||
bottom: -1rem;
|
||||
}
|
||||
@media (max-width: 48rem) {
|
||||
.welcome-content__body {
|
||||
.intro-content__body {
|
||||
margin-top: -9.8rem;
|
||||
}
|
||||
.welcome-content__body:before,
|
||||
.welcome-content__body:after {
|
||||
.intro-content__body:before,
|
||||
.intro-content__body:after {
|
||||
inset: unset;
|
||||
}
|
||||
}
|
||||
@media (min-width: 64rem) {
|
||||
.welcome-content {
|
||||
.intro-content {
|
||||
margin-top: 0;
|
||||
}
|
||||
.welcome-content__body {
|
||||
.intro-content__body {
|
||||
margin-top: -5.7rem;
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-poweredby {
|
||||
.intro-button {
|
||||
width: 100%;
|
||||
margin: 0 auto 3rem;
|
||||
z-index: 10;
|
||||
}
|
||||
.welcome-poweredby__link {
|
||||
.intro-button__link {
|
||||
background: #7f1d1d;
|
||||
background-image: linear-gradient(to bottom, rgba(255,0,0,0.8), rgba(255,255,255,0));
|
||||
background-position: top left, center;
|
||||
|
@ -196,7 +192,6 @@ a:hover:visited {
|
|||
font-size: 1.5rem;
|
||||
line-height: 1.3;
|
||||
text-decoration: none;
|
||||
/*text-shadow: var(--shadow);*/
|
||||
transition: transform 0.3s ease-in-out;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
@ -204,7 +199,7 @@ a:hover:visited {
|
|||
min-height: 7.6875rem;
|
||||
outline: none;
|
||||
}
|
||||
.welcome-poweredby__link::before {
|
||||
.intro-button__link::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -13.125rem;
|
||||
|
@ -216,7 +211,7 @@ a:hover:visited {
|
|||
transition: transform 0.3s ease-in-out;
|
||||
z-index: 5;
|
||||
}
|
||||
.welcome-poweredby__text {
|
||||
.intro-button__text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
|
@ -226,25 +221,24 @@ a:hover:visited {
|
|||
padding: 1rem 1.5rem;
|
||||
text-align: left;
|
||||
color: white;
|
||||
/*text-shadow: 0 0.101125rem 0.2021875rem rgba(0, 0, 0, 0.25);*/
|
||||
font-size: 1.65rem;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 130.023%;
|
||||
letter-spacing: 0.0075rem;
|
||||
}
|
||||
.welcome-poweredby__text strong {
|
||||
.intro-button__text strong {
|
||||
font-size: 2.625rem;
|
||||
font-weight: 600;
|
||||
line-height: 130.023%;
|
||||
letter-spacing: 0.013125rem;
|
||||
}
|
||||
.welcome-poweredby__link span {
|
||||
.intro-button__link span {
|
||||
position: absolute;
|
||||
display: block;
|
||||
pointer-events: none;
|
||||
}
|
||||
.welcome-poweredby__link span:nth-child(1) {
|
||||
.intro-button__link span:nth-child(1) {
|
||||
height: 8px;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
|
@ -264,7 +258,7 @@ a:hover:visited {
|
|||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
.welcome-poweredby__link span:nth-child(2) {
|
||||
.intro-button__link span:nth-child(2) {
|
||||
width: 8px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
|
@ -284,7 +278,7 @@ a:hover:visited {
|
|||
transform: translateY(100%);
|
||||
}
|
||||
}
|
||||
.welcome-poweredby__link span:nth-child(3) {
|
||||
.intro-button__link span:nth-child(3) {
|
||||
height: 8px;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
|
@ -304,22 +298,22 @@ a:hover:visited {
|
|||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
.welcome-poweredby__link:hover span {
|
||||
.intro-button__link:hover span {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
@media (max-width: 48rem) {
|
||||
.welcome-poweredby__link {
|
||||
.intro-button__link {
|
||||
height: 6.25rem;
|
||||
min-width: auto;
|
||||
border-radius: 0;
|
||||
}
|
||||
.welcome-poweredby__text {
|
||||
.intro-button__text {
|
||||
display: inline;
|
||||
padding-top: .5rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 48rem) {
|
||||
.welcome-poweredby {
|
||||
.intro-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
|
@ -327,14 +321,13 @@ a:hover:visited {
|
|||
max-width: 29.375rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.welcome-poweredby__link:hover {
|
||||
.intro-button__link:hover {
|
||||
transition: all .5s;
|
||||
transform: rotate(-3deg) scale(1.1);
|
||||
/*box-shadow: 0px 3px 5px rgba(0,0,0,.4);*/
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-text {
|
||||
.intro-text {
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
@ -346,13 +339,16 @@ a:hover:visited {
|
|||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
margin-top: -6rem;
|
||||
background: #fff;
|
||||
margin-bottom: 0;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
padding: 6rem 1.063rem 0.75rem;
|
||||
padding: 2.5rem 1.063rem 0.75rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
.welcome-text p {
|
||||
.intro-button + .intro-text {
|
||||
padding-top: 6rem;
|
||||
}
|
||||
.intro-text p {
|
||||
width: 100%;
|
||||
line-height: 150%;
|
||||
font-weight: 400;
|
||||
|
@ -360,14 +356,16 @@ a:hover:visited {
|
|||
margin: 0 0 1.5rem;
|
||||
}
|
||||
@media (min-width: 48rem) {
|
||||
.welcome-text {
|
||||
.intro-text {
|
||||
font-size: 1.375rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
.intro-button + .intro-text {
|
||||
padding-top: 7rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 64rem) {
|
||||
.welcome-text {
|
||||
.intro-text {
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: var(--shadow);
|
||||
max-width: 60rem;
|
||||
|
@ -377,13 +375,13 @@ a:hover:visited {
|
|||
}
|
||||
}
|
||||
|
||||
.welcome-text__block {
|
||||
.intro-text .block {
|
||||
position: relative;
|
||||
}
|
||||
.welcome-text__block h2 {
|
||||
.intro-text .block__title {
|
||||
margin: 1em 0 .8em;
|
||||
}
|
||||
.welcome-text__block h2 span {
|
||||
.intro-text .block__title span {
|
||||
display: inline-block;
|
||||
padding: 10px 30px 14px;
|
||||
margin: 0 0 0 20px;
|
||||
|
@ -394,7 +392,7 @@ a:hover:visited {
|
|||
border-color: orangered;
|
||||
transform: rotate(-3deg) translateY(-25%);
|
||||
}
|
||||
.welcome-text__block h2:before {
|
||||
.intro-text .block__title:before {
|
||||
content: "";
|
||||
height: 5px;
|
||||
position: absolute;
|
||||
|
@ -407,7 +405,7 @@ a:hover:visited {
|
|||
transform: rotate(2deg) translateY(-50%);
|
||||
transform-origin: top left;
|
||||
}
|
||||
.welcome-text__block h2:after {
|
||||
.intro-text .block__title:after {
|
||||
content: "";
|
||||
height: 70rem;
|
||||
position: absolute;
|
||||
|
@ -420,15 +418,17 @@ a:hover:visited {
|
|||
}
|
||||
|
||||
/*
|
||||
* Region footer
|
||||
* Footer
|
||||
*/
|
||||
|
||||
.region--footer {
|
||||
.intro-footer {
|
||||
width: 100%;
|
||||
background-color: black;
|
||||
color: var(--color-gray);
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.welcome-footer {
|
||||
.intro-footer__body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
@ -439,33 +439,33 @@ a:hover:visited {
|
|||
font-weight: 300;
|
||||
line-height: 100%;
|
||||
}
|
||||
.welcome-footer a:visited {
|
||||
.intro-footer__body a:visited {
|
||||
color: var(--color-gray);
|
||||
}
|
||||
.welcome-footer__logo,
|
||||
.welcome-footer__links {
|
||||
.intro-footer__logo,
|
||||
.intro-footer__links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
.welcome-footer__logo {
|
||||
.intro-footer__logo {
|
||||
max-height: 12.625rem;
|
||||
}
|
||||
.welcome-footer__logo svg {
|
||||
.intro-footer__logo svg {
|
||||
width: 100%;
|
||||
}
|
||||
.welcome-footer__links {
|
||||
.intro-footer__links {
|
||||
gap: 1.875rem;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
@media (max-width: 48rem) {
|
||||
.welcome-footer__logo {
|
||||
.intro-footer__logo {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 64rem) {
|
||||
.welcome-footer {
|
||||
.intro-footer__body {
|
||||
padding: 0 1rem 2rem;
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 180 KiB |
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 183 KiB |