diff --git a/src/base.rs b/src/base.rs index 6f22dd7..d27a9ad 100644 --- a/src/base.rs +++ b/src/base.rs @@ -1,7 +1,9 @@ -//! Reúne acciones, componentes y temas listos para usar. +//! Reúne acciones, componentes, extensiones y temas predefinidos. pub mod action; pub mod component; +pub mod extension; + pub mod theme; diff --git a/src/base/extension.rs b/src/base/extension.rs new file mode 100644 index 0000000..49e408d --- /dev/null +++ b/src/base/extension.rs @@ -0,0 +1,4 @@ +//! Extensiones para funcionalidades avanzadas de `PageTop`. + +mod welcome; +pub use welcome::Welcome; diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs new file mode 100644 index 0000000..f0664d2 --- /dev/null +++ b/src/base/extension/welcome.rs @@ -0,0 +1,108 @@ +use crate::prelude::*; + +/// Página de bienvenida predeterminada de `PageTop`. +/// +/// Esta extensión se instala por defecto y muestra una página en la ruta raíz (`/`) cuando no se ha +/// configurado ninguna página de inicio personalizada. Permite confirmar que el servidor está +/// funcionando correctamente. +pub struct Welcome; + +impl ExtensionTrait for Welcome { + fn name(&self) -> L10n { + L10n::l("welcome_extension_name") + } + + fn description(&self) -> L10n { + L10n::l("welcome_extension_description") + } + + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + scfg.route("/", service::web::get().to(homepage)); + } +} + +async fn homepage(request: HttpRequest) -> ResultPage { + let app = &global::SETTINGS.app.name; + + Page::new(request) + .with_title(L10n::l("welcome_page")) + .with_theme("Basic") + .with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/welcome.css"))) + .with_component(Html::with(html! { + div id="main-header" { + header { + h1 id="header-title" aria-label=(L10n::l("welcome_aria").with_arg("app", app)) { + span { (L10n::l("welcome_title")) } + (L10n::l("welcome_intro").with_arg("app", app)) + } + } + aside id="header-image" aria-hidden="true" { + div id="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 id="main-content" { + section class="content-body" { + div id="poweredby-button" { + a id="poweredby-link" href="https://pagetop.cillero.es" target="_blank" rel="noreferrer" { + span {} span {} span {} + div id="poweredby-text" { (L10n::l("welcome_powered")) } + } + } + div class="content-text" { + p { (L10n::l("welcome_text1")) } + p { (L10n::l("welcome_text2")) } + + div class="subcontent" { + h1 { span { (L10n::l("welcome_about")) } } + p { (L10n::l("welcome_pagetop")) } + p { (L10n::l("welcome_issues1")) } + p { (L10n::l("welcome_issues2").with_arg("app", app)) } + } + } + } + } + + footer id="footer" { + section class="footer-inner" { + div class="footer-logo" { + svg + viewBox="0 0 1614 1614" + xmlns="http://www.w3.org/2000/svg" + role="img" + aria-label=(L10n::l("pagetop_logo")) + 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="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")) } + em { (L10n::l("welcome_have_fun")) } + } + } + } + + })) + .render() +} diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 0fc533c..4ea2460 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -11,4 +11,12 @@ impl ExtensionTrait for Basic { } } -impl ThemeTrait for Basic {} +impl ThemeTrait for Basic { + fn after_render_page_body(&self, page: &mut Page) { + page.alter_assets(AssetsOp::AddStyleSheet( + StyleSheet::from("/css/normalize.css") + .with_version("8.0.1") + .with_weight(-99), + )); + } +} diff --git a/src/core/extension/all.rs b/src/core/extension/all.rs index f061044..93b5c4b 100644 --- a/src/core/extension/all.rs +++ b/src/core/extension/all.rs @@ -29,8 +29,8 @@ pub fn register_extensions(root_extension: Option) { add_to_enabled(&mut enabled_list, extension); } - /* Añade la página de bienvenida por defecto a la lista de extensiones habilitadas. - add_to_enabled(&mut enabled_list, &crate::base::extension::Welcome); */ + // Añade la página de bienvenida por defecto a la lista de extensiones habilitadas. + add_to_enabled(&mut enabled_list, &crate::base::extension::Welcome); // Guarda la lista final de extensiones habilitadas. ENABLED_EXTENSIONS.write().append(&mut enabled_list); @@ -128,9 +128,18 @@ pub fn initialize_extensions() { include_files!(assets); pub fn configure_services(scfg: &mut service::web::ServiceConfig) { + // Sólo compila durante el desarrollo, para evitar errores 400 en la traza de eventos. + #[cfg(debug_assertions)] + scfg.route( + // Ruta automática lanzada por Chrome DevTools. + "/.well-known/appspecific/com.chrome.devtools.json", + service::web::get().to(|| async { service::HttpResponse::NotFound().finish() }), + ); + for extension in ENABLED_EXTENSIONS.read().iter() { extension.configure_service(scfg); } + include_files_service!( scfg, assets => "/", [&global::SETTINGS.dev.pagetop_project_dir, "static"] ); diff --git a/src/global.rs b/src/global.rs index faa9c2f..f150ca6 100644 --- a/src/global.rs +++ b/src/global.rs @@ -6,7 +6,7 @@ use serde::Deserialize; include_config!(SETTINGS: Settings => [ // [app] - "app.name" => "Sample", + "app.name" => "PageTop App", "app.description" => "Developed with the amazing PageTop framework.", "app.theme" => "Basic", "app.language" => "en-US", diff --git a/src/lib.rs b/src/lib.rs index 63ca6a5..598c55e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,7 +98,7 @@ pub mod core; pub mod response; // Gestión del servidor y servicios web. pub mod service; -// Reúne acciones, componentes y temas listos para usar. +// Reúne acciones, componentes, extensiones y temas predefinidos. pub mod base; // Prepara y ejecuta la aplicación. pub mod app; diff --git a/src/locale.rs b/src/locale.rs index 298b350..2a08ba6 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -90,7 +90,7 @@ //! Y *voilà*, sólo queda operar con los idiomas soportados por `PageTop` usando [`LangMatch`] y //! traducir textos con [`L10n`]. -use crate::html::{Markup, PreEscaped}; +use crate::html::{Markup, PreEscaped, Render}; use crate::{global, hm, AutoDefault}; pub use fluent_templates; @@ -313,7 +313,7 @@ enum L10nOp { /// // Traducción simple con clave y argumentos. /// let hello = L10n::l("greeting") /// .with_arg("name", "Manuel") -/// .markup(); +/// .get(); /// ``` /// /// También para traducciones a idiomas concretos. @@ -400,17 +400,19 @@ impl L10n { } } - /// Traduce y escapa con el idioma por defecto, devolviendo [`Markup`]. - pub fn markup(&self) -> Markup { - PreEscaped(self.get().unwrap_or_default()) - } - /// Traduce y escapa con el [`LanguageIdentifier`] indicado, devolviendo [`Markup`]. pub fn escaped(&self, langid: &LanguageIdentifier) -> Markup { PreEscaped(self.using(langid).unwrap_or_default()) } } +impl Render for L10n { + /// Traduce y escapa con el idioma por defecto, devolviendo [`Markup`]. + fn render(&self) -> Markup { + PreEscaped(self.get().unwrap_or_default()) + } +} + impl fmt::Debug for L10n { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("L10n") diff --git a/src/locale/en-US/theme.ftl b/src/locale/en-US/theme.ftl index fd7f228..9c71e6b 100644 --- a/src/locale/en-US/theme.ftl +++ b/src/locale/en-US/theme.ftl @@ -1 +1,2 @@ content = Content +pagetop_logo = PageTop Logo diff --git a/src/locale/en-US/welcome.ftl b/src/locale/en-US/welcome.ftl new file mode 100644 index 0000000..7d98f44 --- /dev/null +++ b/src/locale/en-US/welcome.ftl @@ -0,0 +1,21 @@ +welcome_extension_name = Default homepage +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 PageTop! + +welcome_text1 = If you can read this page, it means that the PageTop server is running correctly but has not yet been fully configured. This usually means the site is either experiencing temporary issues or is undergoing routine maintenance. +welcome_text2 = If the issue persists, please contact your system administrator for assistance. + +welcome_about = About +welcome_pagetop = PageTop is a Rust-based web development framework for building modular, extensible, and configurable web solutions. + +welcome_issues1 = To report issues related to the PageTop framework, please use SoloGit. Before opening a new issue, check existing reports to avoid duplicates. +welcome_issues2 = For issues related specifically to { $app }, please refer to its official repository or support channel, rather than directly to PageTop. + +welcome_code = Code +welcome_have_fun = Coding is creating diff --git a/src/locale/es-ES/theme.ftl b/src/locale/es-ES/theme.ftl index c2026c6..f193c53 100644 --- a/src/locale/es-ES/theme.ftl +++ b/src/locale/es-ES/theme.ftl @@ -1 +1,2 @@ content = Contenido +pagetop_logo = Logotipo de PageTop diff --git a/src/locale/es-ES/welcome.ftl b/src/locale/es-ES/welcome.ftl new file mode 100644 index 0000000..8a38425 --- /dev/null +++ b/src/locale/es-ES/welcome.ftl @@ -0,0 +1,21 @@ +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_aria = Saluda a tu instalación { $app } + +welcome_intro = Descubre⚡{ $app } +welcome_powered = Una solución web creada con PageTop! + +welcome_text1 = Si puedes leer esta página, significa que el servidor de PageTop funciona correctamente, pero aún no ha sido completamente configurado. Esto suele indicar que el sitio está experimentando problemas temporales o está pasando por un mantenimiento de rutina. +welcome_text2 = Si el problema persiste, por favor contacta con el administrador del sistema para recibir asistencia técnica. + +welcome_about = Acerca de +welcome_pagetop = PageTop es un entorno de desarrollo web basado en Rust, diseñado para crear soluciones web modulares, extensibles y configurables. + +welcome_issues1 = Para comunicar cualquier problema con PageTop, utiliza SoloGit. Antes de informar de una incidencia, revisa los informes ya existentes para evitar duplicados. +welcome_issues2 = Si se trata de fallos específicos de { $app }, por favor acude a su repositorio oficial o canal de soporte, y no al de PageTop directamente. + +welcome_code = Código +welcome_have_fun = Programar es crear diff --git a/static/css/normalize.css b/static/css/normalize.css new file mode 100644 index 0000000..192eb9c --- /dev/null +++ b/static/css/normalize.css @@ -0,0 +1,349 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Render the `main` element consistently in IE. + */ + +main { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} diff --git a/static/css/welcome.css b/static/css/welcome.css new file mode 100644 index 0000000..8f60348 --- /dev/null +++ b/static/css/welcome.css @@ -0,0 +1,460 @@ +: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-color: #8c5919; + --color: #1a202c; + --color-red: #fecaca; + --color-gray: #e4e4e7; + --color-link: #1e4eae; + --focus-outline: 2px solid var(--color-link); + --focus-outline-offset: 2px; + --shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); +} + +html { + min-height: 100%; + background-color: black; +} +body { + margin: auto; + position: relative; + min-height: 100%; + min-width: 350px; + background-color: var(--bg-color); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + font-size: 1.125rem; + font-weight: 300; + color: var(--color); + line-height: 1.6; +} + +header, +section { + position: relative; + text-align: center; +} + +a { + color: currentColor; + text-decoration: underline; + transition: font-size 0.2s, text-decoration-color 0.2s; +} +a:focus-visible { + outline: var(--focus-outline); + outline-offset: var(--focus-outline-offset); +} +a:hover, +a:hover:visited { + text-decoration-color: var(--color-link); +} + +#content { + width: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +#main-header { + display: flex; + flex-direction: column-reverse; + padding-bottom: 9rem; + max-width: 80rem; + width: 100%; + background-image: var(--bg-img-sm); + background-image: var(--bg-img-sm-set); + background-position: top center; + background-position-y: -1rem; + background-size: contain; + background-repeat: no-repeat; +} +#main-header header { + padding: 0; + background: none; +} +#header-title { + margin: 0 0 0 1.5rem; + text-align: left; + display: flex; + flex-direction: column; + box-sizing: border-box; + color: #dceefb; + padding: clamp(0rem, -5.4892rem + 23.4206vw, 9.5rem) 1rem 1rem; + font-size: clamp(1.5rem, 0.7231rem + 3.3149vw, 3.375rem); + font-style: italic; + font-weight: 600; + line-height: 110%; + text-shadow: 0 0.125rem 0.1875rem rgba(0, 0, 0, 0.3); +} +#header-title > span { + background: linear-gradient(180deg, #ddff95 30%, #ffb84b 100%); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + font-size: clamp(2.25rem, 1.3177rem + 3.9779vw, 6.5rem); + font-style: normal; + font-weight: 700; + line-height: 110%; + text-shadow: none; +} +#header-image { + width: 100%; + text-align: right; + display: flex; + justify-content: flex-start; +} +#header-image #monster { + margin-right: 12rem; + margin-top: 1rem; + flex-shrink: 1; +} +@media (min-width: 64rem) { + #main-header { + background-image: var(--bg-img); + background-image: var(--bg-img-set); + } + #header-title { + padding: 1.2rem 2rem 2.6rem 2rem; + } + #header-image { + justify-content: flex-end; + } +} + +#main-content { + height: auto; + margin-top: 1.6rem; +} +.content-body { + box-sizing: border-box; + max-width: 80rem; +} +.content-body:before, +.content-body:after { + content: ''; + position: absolute; + left: 0; + right: 0; + background: linear-gradient(130deg, rgba(13, 44, 91, 0) 0%, #ddff95 77.4%); + margin: 0 -10.375rem; + filter: blur(2.75rem); + opacity: 0.8; + inset: 11.75rem; + z-index: 0; +} +.content-body:before { + top: -1rem; +} +.content-body:after { + bottom: -1rem; +} +@media (max-width: 48rem) { + .content-body { + margin-top: -9.8rem; + } + .content-body:before, + .content-body:after { + inset: unset; + } +} +@media (min-width: 64rem) { + #main-content { + margin-top: 0; + } + .content-body { + margin-top: -5.7rem; + } +} + +#poweredby-button { + width: 100%; + margin: 0 auto 3rem; + z-index: 10; +} +#poweredby-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; + background-size: contain; + background-repeat: no-repeat; + border-radius: 0.75rem; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + 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; + min-width: 28.875rem; + min-height: 7.6875rem; + outline: none; +} +#poweredby-link::before { + content: ''; + position: absolute; + top: -13.125rem; + left: -10rem; + height: 26.25rem; + width: 26.25rem; + background: linear-gradient(135deg, #ec7bae 50.41%, #9600b8 70.41%); + transform: rotate(45deg); + transition: transform 0.3s ease-in-out; + z-index: 5; +} +#poweredby-text { + display: flex; + flex-direction: column; + flex: 1; + transition: all 0.5s ease-in-out; + position: relative; + z-index: 10; + 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; +} +#poweredby-text strong { + font-size: 2.625rem; + font-weight: 600; + line-height: 130.023%; + letter-spacing: 0.013125rem; +} +#poweredby-link span { + position: absolute; + display: block; + pointer-events: none; +} +#poweredby-link span:nth-child(1) { + height: 8px; + width: 100%; + top: 0; + left: 0; + background: linear-gradient(to right, rgba(0, 0, 0, 0), #f6e58d); + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + transform: translateX(-100%); + animation: span1 8s linear infinite; + animation-delay: 1s; +} +@keyframes span1 { + 0% { + transform: translateX(-100%); + } + 100% { + transform: translateX(100%); + } +} +#poweredby-link span:nth-child(2) { + width: 8px; + height: 100%; + top: 0; + right: 0; + background: linear-gradient(to bottom, rgba(0, 0, 0, 0), #f6e58d); + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + transform: translateY(100%); + animation: span2 4s linear infinite; + animation-delay: 5s; +} +@keyframes span2 { + 0% { + transform: translateY(-100%); + } + 100% { + transform: translateY(100%); + } +} +#poweredby-link span:nth-child(3) { + height: 8px; + width: 100%; + bottom: 0; + right: 0; + background: linear-gradient(to left, rgba(0, 0, 0, 0), #f6e58d); + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + transform: translateX(100%); + animation: span3 8s linear infinite; + animation-delay: 7s; +} +@keyframes span3 { + 0% { + transform: translateX(100%); + } + 100% { + transform: translateX(-100%); + } +} +#poweredby-link:hover { + transition: all .5s; + transform: rotate(-3deg) scale(1.1); + box-shadow: 0px 3px 5px rgba(0,0,0,.4); +} +#poweredby-link:hover span { + animation-play-state: paused; +} +@media (max-width: 48rem) { + #poweredby-link { + height: 6.25rem; + min-width: auto; + border-radius: 0; + } + #poweredby-text { + display: inline; + padding-top: .5rem; + } +} +@media (min-width: 48rem) { + #poweredby-button { + position: absolute; + top: 0; + left: 50%; + transform: translate(-50%, -50%); + max-width: 29.375rem; + margin-bottom: 0; + } +} + +.content-text { + z-index: 1; + width: 100%; + display: flex; + flex-direction: column; + box-sizing: border-box; + align-items: center; + text-align: left; + font-size: 1.3125rem; + font-weight: 400; + line-height: 1.5; + margin-top: -6rem; + background: #fff; + margin-bottom: 0; + position: relative; + padding: 6rem 1.063rem 0.75rem; + overflow: hidden; +} +.content-text p { + width: 100%; + line-height: 150%; + font-weight: 400; + font-size: 1.45rem; + margin: 0 0 1.5rem; +} +@media (min-width: 48rem) { + .content-text { + font-size: 1.375rem; + line-height: 2rem; + padding-top: 7rem; + } +} +@media (min-width: 64rem) { + .content-text { + border-radius: 0.75rem; + box-shadow: var(--shadow); + max-width: 60rem; + margin: 0 auto 6rem; + padding-left: 4.5rem; + padding-right: 4.5rem; + } +} + +.subcontent { + position: relative; +} +.subcontent h1 { + margin: 1em 0 .8em; +} +.subcontent h1 span { + display: inline-block; + padding: 10px 30px 14px; + margin: 0 0 0 20px; + background: white; + border: 5px solid; + border-radius: 30px; + box-shadow: 0 0 0 5px white, inset 0 0 0 5px white; + border-color: orangered; + transform: rotate(-3deg) translateY(-25%); +} +.subcontent h1:before { + content: ""; + height: 5px; + position: absolute; + top: 50px; + left: -15%; + width: 130%; + z-index: -5; + background: orangered; + box-shadow: 0 0 0 5px white, 0 -10px 0 5px white; + transform: rotate(2deg) translateY(-50%); + transform-origin: top left; +} +.subcontent h1:after { + content: ""; + height: 70rem; + position: absolute; + top: 42px; + left: -15%; + width: 130%; + z-index: -10; + background: var(--color-red); + transform: rotate(2deg); +} + +#footer { + width: 100%; + background-color: black; + color: var(--color-gray); + font-size: 1.15rem; + font-weight: 300; + line-height: 100%; + display: flex; + justify-content: center; + z-index: 10; +} +#footer a:visited { + color: var(--color-gray); +} +.footer-logo { + max-height: 12.625rem; +} +.footer-logo svg { + width: 100%; +} +.footer-logo, +.footer-links, +.footer-inner { + display: flex; + justify-content: center; + width: 100%; +} +.footer-links { + gap: 1.875rem; + flex-wrap: wrap; + margin-top: 2rem; +} +.footer-inner { + max-width: 80rem; + display: flex; + flex-direction: column; + padding: 0 10.625rem 2rem; +} +@media (max-width: 48rem) { + .footer-logo { + display: none; + } +} +@media (max-width: 64rem) { + .footer-inner { + padding: 0 1rem 2rem; + } +} diff --git a/static/img/monster-pagetop_250.avif b/static/img/monster-pagetop_250.avif new file mode 100644 index 0000000..df864b8 Binary files /dev/null and b/static/img/monster-pagetop_250.avif differ diff --git a/static/img/monster-pagetop_250.png b/static/img/monster-pagetop_250.png new file mode 100644 index 0000000..baa7d1f Binary files /dev/null and b/static/img/monster-pagetop_250.png differ diff --git a/static/img/monster-pagetop_250.webp b/static/img/monster-pagetop_250.webp new file mode 100644 index 0000000..dcc5ef2 Binary files /dev/null and b/static/img/monster-pagetop_250.webp differ diff --git a/static/img/monster-pagetop_500.avif b/static/img/monster-pagetop_500.avif new file mode 100644 index 0000000..d07f359 Binary files /dev/null and b/static/img/monster-pagetop_500.avif differ diff --git a/static/img/monster-pagetop_500.png b/static/img/monster-pagetop_500.png new file mode 100644 index 0000000..d0b9e0b Binary files /dev/null and b/static/img/monster-pagetop_500.png differ diff --git a/static/img/monster-pagetop_500.webp b/static/img/monster-pagetop_500.webp new file mode 100644 index 0000000..18896fe Binary files /dev/null and b/static/img/monster-pagetop_500.webp differ diff --git a/static/img/welcome-header-sm.avif b/static/img/welcome-header-sm.avif new file mode 100644 index 0000000..ec31a6d Binary files /dev/null and b/static/img/welcome-header-sm.avif differ diff --git a/static/img/welcome-header-sm.jpg b/static/img/welcome-header-sm.jpg new file mode 100644 index 0000000..f2c875f Binary files /dev/null and b/static/img/welcome-header-sm.jpg differ diff --git a/static/img/welcome-header-sm.webp b/static/img/welcome-header-sm.webp new file mode 100644 index 0000000..9f7aff8 Binary files /dev/null and b/static/img/welcome-header-sm.webp differ diff --git a/static/img/welcome-header.avif b/static/img/welcome-header.avif new file mode 100644 index 0000000..8018555 Binary files /dev/null and b/static/img/welcome-header.avif differ diff --git a/static/img/welcome-header.jpg b/static/img/welcome-header.jpg new file mode 100644 index 0000000..69f1dbe Binary files /dev/null and b/static/img/welcome-header.jpg differ diff --git a/static/img/welcome-header.webp b/static/img/welcome-header.webp new file mode 100644 index 0000000..7da174c Binary files /dev/null and b/static/img/welcome-header.webp differ diff --git a/tests/service.rs b/tests/service.rs index 51e74c7..5aec398 100644 --- a/tests/service.rs +++ b/tests/service.rs @@ -8,8 +8,5 @@ async fn homepage_returns_404() { let resp = service::test::call_service(&app, req).await; // Comprueba el acceso a la ruta de inicio. - // assert_eq!(resp.status(), service::http::StatusCode::OK); - - // Sin ruta de inicio se obtiene error 404, pero el test funciona. - assert_eq!(resp.status(), service::http::StatusCode::NOT_FOUND); + assert_eq!(resp.status(), service::http::StatusCode::OK); }