♻️ Refactoriza página de bienvenida y tema Basic
- Actualiza `Welcome` para usar el nuevo componente `Intro`. - Simplifica el tema `Basic` apoyándose en la lógica de `Theme`. - Predefine los *assets* básicos como recursos de `Theme`. - Refactoriza archivos de localicación para reflejar los cambios de los componentes.
This commit is contained in:
parent
d0beb8ef40
commit
ebf1828ea3
12 changed files with 455 additions and 296 deletions
|
@ -108,7 +108,7 @@ impl Extension for Aliner {
|
|||
|
||||
impl Theme for Aliner {
|
||||
fn before_render_page_body(&self, page: &mut Page) {
|
||||
page.alter_param("include_basic_css", true)
|
||||
page.alter_param("include_basic_assets", true)
|
||||
.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/aliner/css/styles.css")
|
||||
.with_version(env!("CARGO_PKG_VERSION"))
|
||||
|
|
|
@ -54,6 +54,9 @@ pub use html::Html;
|
|||
mod block;
|
||||
pub use block::Block;
|
||||
|
||||
mod intro;
|
||||
pub use intro::{Intro, IntroOpening};
|
||||
|
||||
mod poweredby;
|
||||
pub use poweredby::PoweredBy;
|
||||
|
||||
|
|
343
src/base/component/intro.rs
Normal file
343
src/base/component/intro.rs
Normal file
|
@ -0,0 +1,343 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
/// Tipo de apertura que se mostrará en la introducción del componente [`Intro`].
|
||||
///
|
||||
/// Permite elegir entre una apertura con textos predefinidos sobre PageTop (como hace la página de
|
||||
/// bienvenida [`Welcome`](crate::base::extension::Welcome)) o una introducción completamente
|
||||
/// personalizada.
|
||||
#[derive(AutoDefault, Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum IntroOpening {
|
||||
/// Modo por defecto. Muestra una introducción estándar de PageTop e incluye automáticamente
|
||||
/// *badges* con información de la última versión liberada, fecha del último lanzamiento y
|
||||
/// licencia de uso.
|
||||
#[default]
|
||||
PageTop,
|
||||
/// Modo totalmente personalizado. No añade *badges* ni textos predefinidos. Usa la imagen de
|
||||
/// PageTop pero el contenido lo define el propio desarrollador.
|
||||
Custom,
|
||||
}
|
||||
|
||||
/// Componente para presentar PageTop (como [`Welcome`](crate::base::extension::Welcome)), o mostrar
|
||||
/// introducciones.
|
||||
///
|
||||
/// Usa la imagen de PageTop para presentar contenidos con:
|
||||
///
|
||||
/// - Una **imagen decorativa** (el *monster* de PageTop) antecediendo al contenido.
|
||||
/// - Una vista destacada con **título + eslogan**.
|
||||
/// - Un **botón opcional** de llamada a la acción con texto y enlace configurables.
|
||||
/// - El **área de textos** con *badges* predefinidos (en modo [`IntroOpening::PageTop`]) y bloques
|
||||
/// ([`Block`](crate::base::component::Block)) para crear párrafos vistosos de texto. Aunque
|
||||
/// admite todo tipo de componentes.
|
||||
///
|
||||
/// ### Ejemplos
|
||||
///
|
||||
/// **Intro mínima por defecto**
|
||||
///
|
||||
/// ```rust
|
||||
/// # use pagetop::prelude::*;
|
||||
/// let intro = Intro::default();
|
||||
/// ```
|
||||
///
|
||||
/// **Título, eslogan y botón personalizados**
|
||||
///
|
||||
/// ```rust
|
||||
/// # use pagetop::prelude::*;
|
||||
/// let intro = Intro::default()
|
||||
/// .with_title(L10n::l("intro_custom_title"))
|
||||
/// .with_slogan(L10n::l("intro_custom_slogan"))
|
||||
/// .with_button(Some((
|
||||
/// L10n::l("intro_learn_more"),
|
||||
/// |_| "/learn-more"
|
||||
/// )));
|
||||
/// ```
|
||||
///
|
||||
/// **Sin botón + modo *Custom* (sin *badges* predefinidos)**
|
||||
///
|
||||
/// ```rust
|
||||
/// # use pagetop::prelude::*;
|
||||
/// let intro = Intro::default()
|
||||
/// .with_button(None::<(L10n, FnPathByContext)>)
|
||||
/// .with_opening(IntroOpening::Custom);
|
||||
/// ```
|
||||
///
|
||||
/// **Añadir contenidos hijo**
|
||||
///
|
||||
/// ```rust
|
||||
/// # use pagetop::prelude::*;
|
||||
/// let intro = Intro::default()
|
||||
/// .add_component(
|
||||
/// Block::new()
|
||||
/// .with_title(L10n::l("intro_custom_block_title"))
|
||||
/// .add_component(Html::with(move |cx| {
|
||||
/// html! {
|
||||
/// p { (L10n::l("intro_custom_paragraph_1").using(cx)) }
|
||||
/// p { (L10n::l("intro_custom_paragraph_2").using(cx)) }
|
||||
/// }
|
||||
/// })),
|
||||
/// );
|
||||
/// ```
|
||||
#[rustfmt::skip]
|
||||
pub struct Intro {
|
||||
title : L10n,
|
||||
slogan : L10n,
|
||||
button : Option<(L10n, FnPathByContext)>,
|
||||
opening : IntroOpening,
|
||||
children: Children,
|
||||
}
|
||||
|
||||
impl Default for Intro {
|
||||
#[rustfmt::skip]
|
||||
fn default() -> Self {
|
||||
Intro {
|
||||
title : L10n::l("intro_default_title"),
|
||||
slogan : L10n::l("intro_default_slogan").with_arg("app", &global::SETTINGS.app.name),
|
||||
button : Some((L10n::l("intro_default_button"), |_| "https://pagetop.cillero.es")),
|
||||
opening : IntroOpening::default(),
|
||||
children: Children::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Intro {
|
||||
fn new() -> Self {
|
||||
Intro::default()
|
||||
}
|
||||
|
||||
fn setup_before_prepare(&mut self, cx: &mut Context) {
|
||||
cx.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/intro.css").with_version(env!("CARGO_PKG_VERSION")),
|
||||
));
|
||||
}
|
||||
|
||||
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
|
||||
if self.opening() == IntroOpening::PageTop {
|
||||
cx.alter_assets(ContextOp::AddJavaScript(JavaScript::on_load_async("intro-js", |cx|
|
||||
util::indoc!(r#"
|
||||
try {
|
||||
const resp = await fetch("https://crates.io/api/v1/crates/pagetop");
|
||||
const data = await resp.json();
|
||||
const date = new Date(data.versions[0].created_at);
|
||||
const formatted = date.toLocaleDateString("LANGID", { year: "numeric", month: "2-digit", day: "2-digit" });
|
||||
document.getElementById("intro-release").src = `https://img.shields.io/badge/Release%20date-${encodeURIComponent(formatted)}-blue?label=LABEL&style=for-the-badge`;
|
||||
document.getElementById("intro-badges").style.display = "block";
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch release date from crates.io:", e);
|
||||
}
|
||||
"#)
|
||||
.replace("LANGID", cx.langid().to_string().as_str())
|
||||
.replace("LABEL", L10n::l("intro_release_label").using(cx).as_str())
|
||||
)));
|
||||
}
|
||||
|
||||
PrepareMarkup::With(html! {
|
||||
div class="intro" {
|
||||
div class="intro-header" {
|
||||
section class="intro-header__body" {
|
||||
h1 class="intro-header__title" {
|
||||
span { (self.title().using(cx)) }
|
||||
(self.slogan().using(cx))
|
||||
}
|
||||
}
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div class="intro-content" {
|
||||
section class="intro-content__body" {
|
||||
div class="intro-text" {
|
||||
@if let Some((txt, lnk)) = self.button() {
|
||||
div class="intro-button" {
|
||||
a
|
||||
class="intro-button__link"
|
||||
href=((lnk)(cx))
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
{
|
||||
span {} span {} span {}
|
||||
div class="intro-button__text" {
|
||||
(txt.using(cx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div class="intro-text__children" {
|
||||
@if self.opening() == IntroOpening::PageTop {
|
||||
p { (L10n::l("intro_text1").using(cx)) }
|
||||
div id="intro-badges" {
|
||||
img
|
||||
src="https://img.shields.io/crates/v/pagetop.svg?label=PageTop&style=for-the-badge"
|
||||
alt=[L10n::l("intro_pagetop_label").lookup(cx)] {} (" ")
|
||||
img
|
||||
id="intro-release"
|
||||
alt=[L10n::l("intro_release_label").lookup(cx)] {} (" ")
|
||||
img
|
||||
src=(format!(
|
||||
"https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label={}&style=for-the-badge",
|
||||
L10n::l("intro_license_label").lookup(cx).unwrap_or_default()
|
||||
))
|
||||
alt=[L10n::l("intro_license_label").lookup(cx)] {}
|
||||
}
|
||||
p { (L10n::l("intro_text2").using(cx)) }
|
||||
}
|
||||
(self.children().render(cx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div 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(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="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("intro_code").using(cx)) }
|
||||
em { (L10n::l("intro_have_fun").using(cx)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Intro {
|
||||
// **< Intro BUILDER >**************************************************************************
|
||||
|
||||
/// Establece el título de entrada.
|
||||
///
|
||||
/// # Ejemplo
|
||||
///
|
||||
/// ```rust
|
||||
/// # use pagetop::prelude::*;
|
||||
/// let intro = Intro::default().with_title(L10n::n("Título de entrada"));
|
||||
/// ```
|
||||
#[builder_fn]
|
||||
pub fn with_title(mut self, title: L10n) -> Self {
|
||||
self.title = title;
|
||||
self
|
||||
}
|
||||
|
||||
/// Establece el eslogan de entrada (línea secundaria del título).
|
||||
///
|
||||
/// # Ejemplo
|
||||
///
|
||||
/// ```rust
|
||||
/// # use pagetop::prelude::*;
|
||||
/// let intro = Intro::default().with_slogan(L10n::n("Un eslogan para la entrada"));
|
||||
/// ```
|
||||
#[builder_fn]
|
||||
pub fn with_slogan(mut self, slogan: L10n) -> Self {
|
||||
self.slogan = slogan;
|
||||
self
|
||||
}
|
||||
|
||||
/// Configura el botón opcional de llamada a la acción.
|
||||
///
|
||||
/// - Usa `Some((texto, closure_url))` para mostrarlo, donde [`FnPathByContext`] recibe el
|
||||
/// [`Context`] y devuelve la ruta o URL final al pulsar el botón.
|
||||
/// - Usa `None` para ocultarlo.
|
||||
///
|
||||
/// # Ejemplo
|
||||
///
|
||||
/// ```rust
|
||||
/// # use pagetop::prelude::*;
|
||||
/// // Define un botón con texto y una URL fija.
|
||||
/// let intro = Intro::default().with_button(Some((L10n::n("Pulsa este botón"), |_| "/start")));
|
||||
/// // Descarta el botón de la intro.
|
||||
/// let intro_no_button = Intro::default().with_button(None);
|
||||
/// ```
|
||||
#[builder_fn]
|
||||
pub fn with_button(mut self, button: Option<(L10n, FnPathByContext)>) -> Self {
|
||||
self.button = button;
|
||||
self
|
||||
}
|
||||
|
||||
/// Selecciona el tipo de apertura: [`IntroOpening::PageTop`] (por defecto) o
|
||||
/// [`IntroOpening::Custom`].
|
||||
///
|
||||
/// - `PageTop`: añade *badges* automáticos y una presentación de lo que es PageTop.
|
||||
/// - `Custom`: introducción en blanco para añadir cualquier contenido.
|
||||
///
|
||||
/// # Ejemplo
|
||||
///
|
||||
/// ```rust
|
||||
/// # use pagetop::prelude::*;
|
||||
/// let intro = Intro::default().with_opening(IntroOpening::Custom);
|
||||
/// ```
|
||||
#[builder_fn]
|
||||
pub fn with_opening(mut self, opening: IntroOpening) -> Self {
|
||||
self.opening = opening;
|
||||
self
|
||||
}
|
||||
|
||||
/// Añade un nuevo componente hijo a la intro.
|
||||
///
|
||||
/// Si es un bloque ([`Block`]) aplica estilos específicos para destacarlo.
|
||||
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 [`ChildOp`].
|
||||
#[builder_fn]
|
||||
pub fn with_child(mut self, op: ChildOp) -> Self {
|
||||
self.children.alter_child(op);
|
||||
self
|
||||
}
|
||||
|
||||
// **< Intro GETTERS >**************************************************************************
|
||||
|
||||
/// Devuelve el título de entrada.
|
||||
pub fn title(&self) -> &L10n {
|
||||
&self.title
|
||||
}
|
||||
|
||||
/// Devuelve el eslogan de la entrada.
|
||||
pub fn slogan(&self) -> &L10n {
|
||||
&self.slogan
|
||||
}
|
||||
|
||||
/// Devuelve el botón de llamada a la acción, si existe.
|
||||
pub fn button(&self) -> Option<(&L10n, &FnPathByContext)> {
|
||||
self.button.as_ref().map(|(txt, lnk)| (txt, lnk))
|
||||
}
|
||||
|
||||
/// Devuelve el modo de apertura configurado.
|
||||
pub fn opening(&self) -> IntroOpening {
|
||||
self.opening
|
||||
}
|
||||
|
||||
/// Devuelve la lista de hijos (`children`) de la intro.
|
||||
pub fn children(&self) -> &Children {
|
||||
&self.children
|
||||
}
|
||||
}
|
|
@ -26,30 +26,29 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
|
|||
|
||||
Page::new(request)
|
||||
.with_theme("Basic")
|
||||
.with_layout("PageTopIntro")
|
||||
.with_title(L10n::l("welcome_title"))
|
||||
.with_description(L10n::l("welcome_intro").with_arg("app", app))
|
||||
.with_param("intro_button_txt", L10n::l("welcome_powered"))
|
||||
.with_param("intro_button_lnk", "https://pagetop.cillero.es".to_string())
|
||||
.add_component(
|
||||
Block::new()
|
||||
.with_title(L10n::l("welcome_status_title"))
|
||||
.add_component(Html::with(move |cx| {
|
||||
html! {
|
||||
p { (L10n::l("welcome_status_1").using(cx)) }
|
||||
p { (L10n::l("welcome_status_2").using(cx)) }
|
||||
}
|
||||
})),
|
||||
)
|
||||
.add_component(
|
||||
Block::new()
|
||||
.with_title(L10n::l("welcome_support_title"))
|
||||
.add_component(Html::with(move |cx| {
|
||||
html! {
|
||||
p { (L10n::l("welcome_support_1").using(cx)) }
|
||||
p { (L10n::l("welcome_support_2").with_arg("app", app).using(cx)) }
|
||||
}
|
||||
})),
|
||||
Intro::new()
|
||||
.add_component(
|
||||
Block::new()
|
||||
.with_title(L10n::l("welcome_status_title"))
|
||||
.add_component(Html::with(move |cx| {
|
||||
html! {
|
||||
p { (L10n::l("welcome_status_1").using(cx)) }
|
||||
p { (L10n::l("welcome_status_2").using(cx)) }
|
||||
}
|
||||
})),
|
||||
)
|
||||
.add_component(
|
||||
Block::new()
|
||||
.with_title(L10n::l("welcome_support_title"))
|
||||
.add_component(Html::with(move |cx| {
|
||||
html! {
|
||||
p { (L10n::l("welcome_support_1").using(cx)) }
|
||||
p { (L10n::l("welcome_support_2").with_arg("app", app).using(cx)) }
|
||||
}
|
||||
})),
|
||||
),
|
||||
)
|
||||
.render()
|
||||
}
|
||||
|
|
|
@ -4,33 +4,7 @@ use crate::prelude::*;
|
|||
/// El tema básico usa las mismas regiones predefinidas por [`ThemeRegion`].
|
||||
pub type BasicRegion = ThemeRegion;
|
||||
|
||||
/// Tema básico por defecto.
|
||||
///
|
||||
/// Ofrece las siguientes composiciones (*layouts*):
|
||||
///
|
||||
/// - **Composición predeterminada**
|
||||
/// - Renderizado genérico con
|
||||
/// [`ThemePage::render_body()`](crate::core::theme::ThemePage::render_body) usando las regiones
|
||||
/// predefinidas en [`page_regions()`](crate::core::theme::Theme::page_regions).
|
||||
///
|
||||
/// - **`Intro`**
|
||||
/// - Página de entrada con cabecera visual, título y descripción y un botón opcional de llamada a
|
||||
/// la acción. Ideal para una página de inicio o bienvenida en el contexto de PageTop.
|
||||
/// - **Regiones:** `content` (se renderiza dentro de `.intro-content__body`).
|
||||
/// - **Parámetros:**
|
||||
/// - `intro_button_txt` (`L10n`) – Texto del botón.
|
||||
/// - `intro_button_lnk` (`Option<String>`) – URL del botón; si no se indica, el botón no se
|
||||
/// muestra.
|
||||
///
|
||||
/// - **`PageTopIntro`**
|
||||
/// - Variante de `Intro` con textos predefinidos sobre PageTop al inicio del contenido. Añade una
|
||||
/// banda de *badges* con la versión de [PageTop en crates.io](https://crates.io/crates/pagetop)
|
||||
/// más la fecha de la última versión publicada y la licencia de uso.
|
||||
/// - **Regiones:** `content` (igual que `Intro`).
|
||||
/// - **Parámetros:** los mismos que `Intro`.
|
||||
///
|
||||
/// **Nota:** si no se especifica `layout` o el valor no coincide con ninguno de los anteriores, se
|
||||
/// aplica la composición predeterminada.
|
||||
/// Tema básico por defecto que extiende el funcionamiento predeterminado de [`Theme`].
|
||||
pub struct Basic;
|
||||
|
||||
impl Extension for Basic {
|
||||
|
@ -40,180 +14,7 @@ impl Extension for Basic {
|
|||
}
|
||||
|
||||
impl Theme for Basic {
|
||||
fn render_page_body(&self, page: &mut Page) -> Markup {
|
||||
match page.layout() {
|
||||
"Intro" => render_intro(page),
|
||||
"PageTopIntro" => render_pagetop_intro(page),
|
||||
_ => <Self as ThemePage>::render_body(self, page, self.page_regions()),
|
||||
}
|
||||
}
|
||||
|
||||
fn after_render_page_body(&self, page: &mut Page) {
|
||||
let pkg_version = env!("CARGO_PKG_VERSION");
|
||||
|
||||
page.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/normalize.css")
|
||||
.with_version("8.0.1")
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/root.css")
|
||||
.with_version(pkg_version)
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/basic.css")
|
||||
.with_version(pkg_version)
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/components.css")
|
||||
.with_version(pkg_version)
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/menu.css")
|
||||
.with_version(pkg_version)
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_assets(ContextOp::AddJavaScript(
|
||||
JavaScript::defer("/js/menu.js")
|
||||
.with_version(pkg_version)
|
||||
.with_weight(-99),
|
||||
));
|
||||
fn before_render_page_body(&self, page: &mut Page) {
|
||||
page.alter_param("include_basic_assets", true);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_intro(page: &mut Page) -> Markup {
|
||||
page.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/intro.css").with_version(env!("CARGO_PKG_VERSION")),
|
||||
));
|
||||
|
||||
let title = page.title().unwrap_or_default();
|
||||
let intro = page.description().unwrap_or_default();
|
||||
|
||||
let theme = page.context().theme();
|
||||
let h = theme.render_page_region(page, &BasicRegion::Header);
|
||||
let c = theme.render_page_region(page, &BasicRegion::Content);
|
||||
let f = theme.render_page_region(page, &BasicRegion::Footer);
|
||||
|
||||
let intro_button_txt: L10n = page.param_or_default("intro_button_txt");
|
||||
let intro_button_lnk: Option<&String> = page.param("intro_button_lnk");
|
||||
|
||||
html! {
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
(h)
|
||||
}
|
||||
main class="intro-content" {
|
||||
section class="intro-content__body" {
|
||||
div class="intro-text" {
|
||||
@if intro_button_lnk.is_some() {
|
||||
div class="intro-button" {
|
||||
a
|
||||
class="intro-button__link"
|
||||
href=[intro_button_lnk]
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
{
|
||||
span {} span {} span {}
|
||||
div class="intro-button__text" {
|
||||
(intro_button_txt.using(page))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
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("intro_code").using(page)) }
|
||||
em { (L10n::l("intro_have_fun").using(page)) }
|
||||
}
|
||||
}
|
||||
(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_pagetop_intro(page: &mut Page) -> Markup {
|
||||
page.alter_assets(ContextOp::AddJavaScript(JavaScript::on_load_async("intro-js", |cx|
|
||||
util::indoc!(r#"
|
||||
try {
|
||||
const resp = await fetch("https://crates.io/api/v1/crates/pagetop");
|
||||
const data = await resp.json();
|
||||
const date = new Date(data.versions[0].created_at);
|
||||
const formatted = date.toLocaleDateString("LANGID", { year: "numeric", month: "2-digit", day: "2-digit" });
|
||||
document.getElementById("intro-release").src = `https://img.shields.io/badge/Release%20date-${encodeURIComponent(formatted)}-blue?label=LABEL&style=for-the-badge`;
|
||||
document.getElementById("intro-badges").style.display = "block";
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch release date from crates.io:", e);
|
||||
}
|
||||
"#)
|
||||
.replace("LANGID", cx.langid().to_string().as_str())
|
||||
.replace("LABEL", L10n::l("intro_release_label").using(cx).as_str())
|
||||
.to_string(),
|
||||
)))
|
||||
.alter_child_in("content", ChildOp::Prepend(Child::with(Html::with(|cx| html! {
|
||||
p { (L10n::l("intro_text1").using(cx)) }
|
||||
div id="intro-badges" style="display: none; margin-bottom: 1.1rem;" {
|
||||
img
|
||||
src="https://img.shields.io/crates/v/pagetop.svg?label=PageTop&style=for-the-badge"
|
||||
alt=[L10n::l("intro_pagetop_label").lookup(cx)] {} (" ")
|
||||
img
|
||||
id="intro-release"
|
||||
alt=[L10n::l("intro_release_label").lookup(cx)] {} (" ")
|
||||
img
|
||||
src=(format!(
|
||||
"https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label={}&style=for-the-badge",
|
||||
L10n::l("intro_license_label").lookup(cx).unwrap_or_default()
|
||||
))
|
||||
alt=[L10n::l("intro_license_label").lookup(cx)] {}
|
||||
}
|
||||
p { (L10n::l("intro_text2").using(cx)) }
|
||||
}))));
|
||||
|
||||
render_intro(page)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::core::component::{ContextOp, Contextual};
|
||||
use crate::core::extension::Extension;
|
||||
use crate::core::theme::{Region, RegionRef, REGION_CONTENT};
|
||||
use crate::html::{html, Markup};
|
||||
use crate::html::{html, Markup, StyleSheet};
|
||||
use crate::locale::L10n;
|
||||
use crate::response::page::Page;
|
||||
use crate::{global, join};
|
||||
|
@ -241,7 +242,7 @@ pub trait Theme: Extension + ThemePage + Send + Sync {
|
|||
|
||||
/// Renderiza el contenido del `<body>` de la página.
|
||||
///
|
||||
/// Si se sobrescribe este método, se puede volver al comportamiento base con:
|
||||
/// Si se sobrescribe este método, se puede volver al renderizado base con:
|
||||
/// `<Self as ThemePage>::render_body(self, page, self.page_regions())`.
|
||||
#[inline]
|
||||
fn render_page_body(&self, page: &mut Page) -> Markup {
|
||||
|
@ -256,10 +257,29 @@ pub trait Theme: Extension + ThemePage + Send + Sync {
|
|||
|
||||
/// Renderiza el contenido del `<head>` de la página.
|
||||
///
|
||||
/// Si se sobrescribe este método, se puede volver al comportamiento base con:
|
||||
/// Si se sobrescribe este método, se puede volver al renderizado base con:
|
||||
/// `<Self as ThemePage>::render_head(self, page)`.
|
||||
#[inline]
|
||||
fn render_page_head(&self, page: &mut Page) -> Markup {
|
||||
if page.param_or("include_basic_assets", false) {
|
||||
let pkg_version = env!("CARGO_PKG_VERSION");
|
||||
|
||||
page.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/normalize.css")
|
||||
.with_version("8.0.1")
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/root.css")
|
||||
.with_version(pkg_version)
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_assets(ContextOp::AddStyleSheet(
|
||||
StyleSheet::from("/css/basic.css")
|
||||
.with_version(pkg_version)
|
||||
.with_weight(-99),
|
||||
));
|
||||
}
|
||||
<Self as ThemePage>::render_head(self, page)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
# Basic theme, intro layout.
|
||||
# Intro component.
|
||||
intro_default_title = Hello, world!
|
||||
intro_default_slogan = Discover⚡{ $app }
|
||||
intro_default_button = A web solution powered by <strong>PageTop</strong>
|
||||
|
||||
intro_pagetop_label = PageTop version on Crates.io
|
||||
intro_release_label = Release date
|
||||
intro_license_label = License
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
welcome_extension_name = Default Homepage
|
||||
welcome_extension_description = Displays a default homepage when none is configured.
|
||||
|
||||
welcome_page = Welcome page
|
||||
welcome_title = Hello, world!
|
||||
|
||||
welcome_intro = Discover⚡{ $app }
|
||||
welcome_powered = A web solution powered by <strong>PageTop</strong>
|
||||
welcome_title = Welcome page
|
||||
|
||||
welcome_status_title = Status
|
||||
welcome_status_1 = If you can see this page, it means the <strong>PageTop</strong> server is running correctly, but the application is not fully configured. This may be due to routine maintenance or a temporary issue.
|
||||
welcome_status_2 = If the issue persists, please <strong>contact the system administrator</strong>.
|
||||
|
||||
welcome_support_title = Support
|
||||
welcome_support_1 = To report issues with the <strong>PageTop</strong> framework, use <a href="https://git.cillero.es/manuelcillero/pagetop/issues" target="_blank" rel="noreferrer">SoloGit</a>. Remember, before opening a new issue, review the existing ones to avoid duplicates.
|
||||
welcome_support_1 = To report issues with the <strong>PageTop</strong> framework, use <a href="https://github.com/manuelcillero/pagetop/issues" target="_blank" rel="noreferrer">GitHub</a>. Remember, before opening a new issue, review the existing ones to avoid duplicates.
|
||||
welcome_support_2 = For issues specific to the application (<strong>{ $app }</strong>), please use its official repository or support channel.
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
# Basic theme, intro layout.
|
||||
# Intro component.
|
||||
intro_default_title = ¡Hola, mundo!
|
||||
intro_default_slogan = Descubre⚡{ $app }
|
||||
intro_default_button = Una solución web creada con <strong>PageTop</strong>
|
||||
|
||||
intro_pagetop_label = Versión de PageTop en Crates.io
|
||||
intro_release_label = Lanzamiento
|
||||
intro_license_label = Licencia
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
welcome_extension_name = Página de inicio predeterminada
|
||||
welcome_extension_description = Muestra una página de inicio predeterminada cuando no hay ninguna configurada.
|
||||
|
||||
welcome_page = Página de bienvenida
|
||||
welcome_title = ¡Hola, mundo!
|
||||
|
||||
welcome_intro = Descubre⚡{ $app }
|
||||
welcome_powered = Una solución web creada con <strong>PageTop</strong>
|
||||
welcome_title = Página de bienvenida
|
||||
|
||||
welcome_status_title = Estado
|
||||
welcome_status_1 = Si puedes ver esta página, es porque el servidor de <strong>PageTop</strong> está funcionando correctamente, pero la aplicación no está completamente configurada. Esto puede deberse a tareas de mantenimiento o a una incidencia temporal.
|
||||
welcome_status_2 = Si el problema persiste, por favor, <strong>contacta con el administrador del sistema</strong>.
|
||||
|
||||
welcome_support_title = Soporte
|
||||
welcome_support_1 = Para comunicar incidencias del propio entorno <strong>PageTop</strong>, utiliza <a href="https://git.cillero.es/manuelcillero/pagetop/issues" target="_blank" rel="noreferrer">SoloGit</a>. Recuerda, antes de abrir una nueva incidencia, revisa las existentes para evitar duplicados.
|
||||
welcome_support_1 = Para comunicar incidencias del propio entorno <strong>PageTop</strong>, utiliza <a href="https://github.com/manuelcillero/pagetop/issues" target="_blank" rel="noreferrer">GitHub</a>. Recuerda, antes de abrir una nueva incidencia, revisa las existentes para evitar duplicados.
|
||||
welcome_support_2 = Para fallos específicos de la aplicación (<strong>{ $app }</strong>), utiliza su repositorio oficial o su canal de soporte.
|
||||
|
|
|
@ -1,12 +1,24 @@
|
|||
html {
|
||||
min-height: 100%;
|
||||
background-color: black;
|
||||
:root {
|
||||
--intro-bg-img: url('/img/intro-header.jpg');
|
||||
--intro-bg-img-set: image-set(url('/img/intro-header.avif') type('image/avif'), url('/img/intro-header.webp') type('image/webp'), var(--intro-bg-img) type('image/jpeg'));
|
||||
--intro-bg-img-sm: url('/img/intro-header-sm.jpg');
|
||||
--intro-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(--intro-bg-img-sm) type('image/jpeg'));
|
||||
--intro-bg-color: #8c5919;
|
||||
--intro-bg-block-1: #b689ff;
|
||||
--intro-bg-block-2: #fecaca;
|
||||
--intro-bg-block-3: #e6a9e2;
|
||||
--intro-bg-block-4: #ffedca;
|
||||
--intro-bg-block-5: #ffffff;
|
||||
--intro-color: #1a202c;
|
||||
--intro-color-gray: #e4e4e7;
|
||||
--intro-color-link: #1e4eae;
|
||||
--intro-focus-outline: 2px solid var(--intro-color-link);
|
||||
--intro-focus-outline-offset: 2px;
|
||||
--intro-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: auto;
|
||||
.intro {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
min-width: 350px;
|
||||
color: var(--intro-color);
|
||||
background-color: var(--intro-bg-color);
|
||||
|
@ -18,22 +30,22 @@ body {
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
section {
|
||||
.intro section {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a {
|
||||
.intro a {
|
||||
color: currentColor;
|
||||
text-decoration: underline;
|
||||
transition: font-size 0.2s, text-decoration-color 0.2s;
|
||||
}
|
||||
a:focus-visible {
|
||||
.intro a:focus-visible {
|
||||
outline: var(--intro-focus-outline);
|
||||
outline-offset: var(--intro-focus-outline-offset);
|
||||
}
|
||||
a:hover,
|
||||
a:hover:visited {
|
||||
.intro a:hover,
|
||||
.intro a:hover:visited {
|
||||
text-decoration-color: var(--intro-color-link);
|
||||
}
|
||||
|
||||
|
@ -172,8 +184,8 @@ a:hover:visited {
|
|||
justify-content: space-between;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.3;
|
||||
text-decoration: none;
|
||||
transition: transform 0.3s ease-in-out;
|
||||
text-decoration: none !important;
|
||||
transition: transform 0.3s ease-in-out !important;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-width: 28.875rem;
|
||||
|
@ -307,7 +319,7 @@ a:hover:visited {
|
|||
}
|
||||
.intro-button__link:hover {
|
||||
transition: all .5s;
|
||||
transform: rotate(-3deg) scale(1.1);
|
||||
transform: rotate(-3deg) scale(1.125);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,11 +338,11 @@ a:hover:visited {
|
|||
background: #fff;
|
||||
position: relative;
|
||||
}
|
||||
.region--content {
|
||||
.intro-text__children {
|
||||
padding: 2.5rem 1.063rem 0.75rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
.region--content p {
|
||||
.intro-text__children p {
|
||||
width: 100%;
|
||||
line-height: 150%;
|
||||
font-weight: 400;
|
||||
|
@ -342,7 +354,7 @@ a:hover:visited {
|
|||
font-size: 1.375rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
.intro-button + .region--content {
|
||||
.intro-button + .intro-text__children {
|
||||
padding-top: 7rem;
|
||||
}
|
||||
}
|
||||
|
@ -351,7 +363,7 @@ a:hover:visited {
|
|||
padding-bottom: 9rem;;
|
||||
}
|
||||
.intro-text,
|
||||
.region--content {
|
||||
.intro-text__children {
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
.intro-text {
|
||||
|
@ -359,19 +371,19 @@ a:hover:visited {
|
|||
max-width: 60rem;
|
||||
margin: 0 auto 6rem;
|
||||
}
|
||||
.region--content {
|
||||
.intro-text__children {
|
||||
padding-left: 4.5rem;
|
||||
padding-right: 4.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.region--content .block {
|
||||
.intro-text__children .block {
|
||||
position: relative;
|
||||
}
|
||||
.region--content .block__title {
|
||||
.intro-text__children .block__title {
|
||||
margin: 1em 0 .8em;
|
||||
}
|
||||
.region--content .block__title span {
|
||||
.intro-text__children .block__title span {
|
||||
display: inline-block;
|
||||
padding: 10px 30px 14px;
|
||||
margin: 30px 0 0 20px;
|
||||
|
@ -382,7 +394,7 @@ a:hover:visited {
|
|||
border-color: orangered;
|
||||
transform: rotate(-3deg) translateY(-25%);
|
||||
}
|
||||
.region--content .block__title:before {
|
||||
.intro-text__children .block__title:before {
|
||||
content: "";
|
||||
height: 5px;
|
||||
position: absolute;
|
||||
|
@ -395,7 +407,7 @@ a:hover:visited {
|
|||
transform: rotate(2deg) translateY(-50%);
|
||||
transform-origin: top left;
|
||||
}
|
||||
.region--content .block__title:after {
|
||||
.intro-text__children .block__title:after {
|
||||
content: "";
|
||||
height: 70rem;
|
||||
position: absolute;
|
||||
|
@ -406,22 +418,28 @@ a:hover:visited {
|
|||
background: var(--intro-bg-block-1);
|
||||
transform: rotate(2deg);
|
||||
}
|
||||
.region--content .block:nth-of-type(5n+1) .block__title:after {
|
||||
.intro-text__children .block:nth-of-type(5n+1) .block__title:after {
|
||||
background: var(--intro-bg-block-1);
|
||||
}
|
||||
.region--content .block:nth-of-type(5n+2) .block__title:after {
|
||||
.intro-text__children .block:nth-of-type(5n+2) .block__title:after {
|
||||
background: var(--intro-bg-block-2);
|
||||
}
|
||||
.region--content .block:nth-of-type(5n+3) .block__title:after {
|
||||
.intro-text__children .block:nth-of-type(5n+3) .block__title:after {
|
||||
background: var(--intro-bg-block-3);
|
||||
}
|
||||
.region--content .block:nth-of-type(5n+4) .block__title:after {
|
||||
.intro-text__children .block:nth-of-type(5n+4) .block__title:after {
|
||||
background: var(--intro-bg-block-4);
|
||||
}
|
||||
.region--content .block:nth-of-type(5n+5) .block__title:after {
|
||||
.intro-text__children .block:nth-of-type(5n+5) .block__title:after {
|
||||
background: var(--intro-bg-block-5);
|
||||
}
|
||||
|
||||
#intro-badges {
|
||||
display: none;
|
||||
margin-bottom: 1.1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*
|
||||
* Footer
|
||||
*/
|
||||
|
@ -474,9 +492,3 @@ a:hover:visited {
|
|||
padding: 0 1rem 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* PoweredBy component */
|
||||
|
||||
.poweredby a:visited {
|
||||
color: var(--intro-color-gray);
|
||||
}
|
||||
|
|
|
@ -1,22 +1,3 @@
|
|||
:root {
|
||||
--intro-bg-img: url('/img/intro-header.jpg');
|
||||
--intro-bg-img-set: image-set(url('/img/intro-header.avif') type('image/avif'), url('/img/intro-header.webp') type('image/webp'), var(--intro-bg-img) type('image/jpeg'));
|
||||
--intro-bg-img-sm: url('/img/intro-header-sm.jpg');
|
||||
--intro-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(--intro-bg-img-sm) type('image/jpeg'));
|
||||
--intro-bg-color: #8c5919;
|
||||
--intro-bg-block-1: #b689ff;
|
||||
--intro-bg-block-2: #fecaca;
|
||||
--intro-bg-block-3: #e6a9e2;
|
||||
--intro-bg-block-4: #ffedca;
|
||||
--intro-bg-block-5: #ffffff;
|
||||
--intro-color: #1a202c;
|
||||
--intro-color-gray: #e4e4e7;
|
||||
--intro-color-link: #1e4eae;
|
||||
--intro-focus-outline: 2px solid var(--intro-color-link);
|
||||
--intro-focus-outline-offset: 2px;
|
||||
--intro-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
:root {
|
||||
--val-font-sans: system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
||||
--val-font-serif: "Lora","georgia",serif;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue